feat: Add Model gestion for piece and component
This commit is contained in:
21
package-lock.json
generated
21
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
"@nestjs/config": "^4.0.2",
|
"@nestjs/config": "^4.0.2",
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
|
"@nestjs/mapped-types": "^2.0.5",
|
||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@prisma/client": "^6.12.0",
|
"@prisma/client": "^6.12.0",
|
||||||
@@ -2535,6 +2536,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/mapped-types": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||||
|
"class-transformer": "^0.4.0 || ^0.5.0",
|
||||||
|
"class-validator": "^0.13.0 || ^0.14.0",
|
||||||
|
"reflect-metadata": "^0.1.12 || ^0.2.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"class-transformer": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"class-validator": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/platform-express": {
|
"node_modules/@nestjs/platform-express": {
|
||||||
"version": "11.1.5",
|
"version": "11.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.5.tgz",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
"@nestjs/config": "^4.0.2",
|
"@nestjs/config": "^4.0.2",
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
|
"@nestjs/mapped-types": "^2.0.5",
|
||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@prisma/client": "^6.12.0",
|
"@prisma/client": "^6.12.0",
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ModelCategory" AS ENUM ('COMPONENT', 'PIECE');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ModelType" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" VARCHAR(120) NOT NULL,
|
||||||
|
"code" VARCHAR(60) NOT NULL,
|
||||||
|
"category" "ModelCategory" NOT NULL,
|
||||||
|
"notes" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ModelType_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ModelType_code_key" ON "ModelType"("code");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ModelType_category_name_idx" ON "ModelType"("category", "name");
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the `type_composants` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "composant_models" DROP CONSTRAINT "composant_models_typeComposantId_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "composants" DROP CONSTRAINT "composants_typeComposantId_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "custom_fields" DROP CONSTRAINT "custom_fields_typeComposantId_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "type_machine_component_requirements" DROP CONSTRAINT "type_machine_component_requirements_typeComposantId_fkey";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "ModelType" ADD COLUMN "description" TEXT;
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "type_composants";
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "composants" ADD CONSTRAINT "composants_typeComposantId_fkey" FOREIGN KEY ("typeComposantId") REFERENCES "ModelType"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "custom_fields" ADD CONSTRAINT "custom_fields_typeComposantId_fkey" FOREIGN KEY ("typeComposantId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "composant_models" ADD CONSTRAINT "composant_models_typeComposantId_fkey" FOREIGN KEY ("typeComposantId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "type_machine_component_requirements" ADD CONSTRAINT "type_machine_component_requirements_typeComposantId_fkey" FOREIGN KEY ("typeComposantId") REFERENCES "ModelType"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Migration: migrate legacy TypePiece references to ModelType entries
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- Insert existing type_pieces into ModelType if not already present
|
||||||
|
INSERT INTO "ModelType" ("id", "name", "code", "category", "notes", "description", "createdAt", "updatedAt")
|
||||||
|
SELECT
|
||||||
|
tp."id",
|
||||||
|
tp."name",
|
||||||
|
tp."id" AS "code",
|
||||||
|
'PIECE'::"ModelCategory",
|
||||||
|
tp."description",
|
||||||
|
tp."description",
|
||||||
|
tp."createdAt",
|
||||||
|
tp."updatedAt"
|
||||||
|
FROM "type_pieces" tp
|
||||||
|
ON CONFLICT ("id") DO NOTHING;
|
||||||
|
|
||||||
|
-- Drop existing foreign keys referencing type_pieces
|
||||||
|
ALTER TABLE "pieces" DROP CONSTRAINT IF EXISTS "pieces_typePieceId_fkey";
|
||||||
|
ALTER TABLE "custom_fields" DROP CONSTRAINT IF EXISTS "custom_fields_typePieceId_fkey";
|
||||||
|
ALTER TABLE "piece_models" DROP CONSTRAINT IF EXISTS "piece_models_typePieceId_fkey";
|
||||||
|
ALTER TABLE "type_machine_piece_requirements" DROP CONSTRAINT IF EXISTS "type_machine_piece_requirements_typePieceId_fkey";
|
||||||
|
|
||||||
|
-- Drop legacy table
|
||||||
|
DROP TABLE IF EXISTS "type_pieces";
|
||||||
|
|
||||||
|
-- Recreate foreign keys pointing to ModelType
|
||||||
|
ALTER TABLE "pieces"
|
||||||
|
ADD CONSTRAINT "pieces_typePieceId_fkey"
|
||||||
|
FOREIGN KEY ("typePieceId") REFERENCES "ModelType"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "custom_fields"
|
||||||
|
ADD CONSTRAINT "custom_fields_typePieceId_fkey"
|
||||||
|
FOREIGN KEY ("typePieceId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "piece_models"
|
||||||
|
ADD CONSTRAINT "piece_models_typePieceId_fkey"
|
||||||
|
FOREIGN KEY ("typePieceId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "type_machine_piece_requirements"
|
||||||
|
ADD CONSTRAINT "type_machine_piece_requirements_typePieceId_fkey"
|
||||||
|
FOREIGN KEY ("typePieceId") REFERENCES "ModelType"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -51,38 +51,6 @@ model TypeMachine {
|
|||||||
@@map("type_machines")
|
@@map("type_machines")
|
||||||
}
|
}
|
||||||
|
|
||||||
model TypeComposant {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
name String @unique
|
|
||||||
description String?
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
// Relations
|
|
||||||
composants Composant[]
|
|
||||||
customFields CustomField[] @relation("TypeComposantCustomFields")
|
|
||||||
models ComposantModel[]
|
|
||||||
componentRequirements TypeMachineComponentRequirement[]
|
|
||||||
|
|
||||||
@@map("type_composants")
|
|
||||||
}
|
|
||||||
|
|
||||||
model TypePiece {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
name String @unique
|
|
||||||
description String?
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
// Relations
|
|
||||||
pieces Piece[]
|
|
||||||
customFields CustomField[] @relation("TypePieceCustomFields")
|
|
||||||
models PieceModel[]
|
|
||||||
pieceRequirements TypeMachinePieceRequirement[]
|
|
||||||
|
|
||||||
@@map("type_pieces")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Machine {
|
model Machine {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
@@ -128,7 +96,7 @@ model Composant {
|
|||||||
sousComposants Composant[] @relation("ComposantHierarchy")
|
sousComposants Composant[] @relation("ComposantHierarchy")
|
||||||
|
|
||||||
typeComposantId String?
|
typeComposantId String?
|
||||||
typeComposant TypeComposant? @relation(fields: [typeComposantId], references: [id])
|
typeComposant ModelType? @relation("ModelTypeComponentAssignments", fields: [typeComposantId], references: [id])
|
||||||
|
|
||||||
composantModelId String?
|
composantModelId String?
|
||||||
composantModel ComposantModel? @relation(fields: [composantModelId], references: [id], onDelete: SetNull)
|
composantModel ComposantModel? @relation(fields: [composantModelId], references: [id], onDelete: SetNull)
|
||||||
@@ -163,7 +131,7 @@ model Piece {
|
|||||||
composant Composant? @relation(fields: [composantId], references: [id], onDelete: Cascade)
|
composant Composant? @relation(fields: [composantId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
typePieceId String?
|
typePieceId String?
|
||||||
typePiece TypePiece? @relation(fields: [typePieceId], references: [id])
|
typePiece ModelType? @relation("ModelTypePieceAssignments", fields: [typePieceId], references: [id])
|
||||||
|
|
||||||
pieceModelId String?
|
pieceModelId String?
|
||||||
pieceModel PieceModel? @relation(fields: [pieceModelId], references: [id], onDelete: SetNull)
|
pieceModel PieceModel? @relation(fields: [pieceModelId], references: [id], onDelete: SetNull)
|
||||||
@@ -180,6 +148,33 @@ model Piece {
|
|||||||
@@map("pieces")
|
@@map("pieces")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ModelCategory {
|
||||||
|
COMPONENT
|
||||||
|
PIECE
|
||||||
|
}
|
||||||
|
|
||||||
|
model ModelType {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String @db.VarChar(120)
|
||||||
|
code String @unique @db.VarChar(60)
|
||||||
|
category ModelCategory
|
||||||
|
notes String? @db.Text
|
||||||
|
description String? @db.Text
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([category, name])
|
||||||
|
|
||||||
|
composants Composant[] @relation("ModelTypeComponentAssignments")
|
||||||
|
models ComposantModel[] @relation("ModelTypeComponentModels")
|
||||||
|
componentRequirements TypeMachineComponentRequirement[] @relation("ModelTypeComponentRequirements")
|
||||||
|
customFields CustomField[] @relation("ModelTypeCustomFields")
|
||||||
|
pieceModels PieceModel[] @relation("ModelTypePieceModels")
|
||||||
|
pieceRequirements TypeMachinePieceRequirement[] @relation("ModelTypePieceRequirements")
|
||||||
|
pieces Piece[] @relation("ModelTypePieceAssignments")
|
||||||
|
pieceCustomFields CustomField[] @relation("ModelTypePieceCustomFields")
|
||||||
|
}
|
||||||
|
|
||||||
model Constructeur {
|
model Constructeur {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
@@ -247,10 +242,10 @@ model CustomField {
|
|||||||
typeMachine TypeMachine? @relation("TypeMachineCustomFields", fields: [typeMachineId], references: [id], onDelete: Cascade)
|
typeMachine TypeMachine? @relation("TypeMachineCustomFields", fields: [typeMachineId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
typeComposantId String?
|
typeComposantId String?
|
||||||
typeComposant TypeComposant? @relation("TypeComposantCustomFields", fields: [typeComposantId], references: [id], onDelete: Cascade)
|
typeComposant ModelType? @relation("ModelTypeCustomFields", fields: [typeComposantId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
typePieceId String?
|
typePieceId String?
|
||||||
typePiece TypePiece? @relation("TypePieceCustomFields", fields: [typePieceId], references: [id], onDelete: Cascade)
|
typePiece ModelType? @relation("ModelTypePieceCustomFields", fields: [typePieceId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
// Relations avec les valeurs
|
// Relations avec les valeurs
|
||||||
customFieldValues CustomFieldValue[]
|
customFieldValues CustomFieldValue[]
|
||||||
@@ -289,7 +284,7 @@ model ComposantModel {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
typeComposantId String
|
typeComposantId String
|
||||||
typeComposant TypeComposant @relation(fields: [typeComposantId], references: [id], onDelete: Cascade)
|
typeComposant ModelType @relation("ModelTypeComponentModels", fields: [typeComposantId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
composants Composant[]
|
composants Composant[]
|
||||||
|
|
||||||
@@ -305,7 +300,7 @@ model PieceModel {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
typePieceId String
|
typePieceId String
|
||||||
typePiece TypePiece @relation(fields: [typePieceId], references: [id], onDelete: Cascade)
|
typePiece ModelType @relation("ModelTypePieceModels", fields: [typePieceId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
pieces Piece[]
|
pieces Piece[]
|
||||||
|
|
||||||
@@ -326,7 +321,7 @@ model TypeMachineComponentRequirement {
|
|||||||
typeMachine TypeMachine @relation(fields: [typeMachineId], references: [id], onDelete: Cascade)
|
typeMachine TypeMachine @relation(fields: [typeMachineId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
typeComposantId String
|
typeComposantId String
|
||||||
typeComposant TypeComposant @relation(fields: [typeComposantId], references: [id])
|
typeComposant ModelType @relation("ModelTypeComponentRequirements", fields: [typeComposantId], references: [id])
|
||||||
|
|
||||||
composants Composant[]
|
composants Composant[]
|
||||||
|
|
||||||
@@ -347,7 +342,7 @@ model TypeMachinePieceRequirement {
|
|||||||
typeMachine TypeMachine @relation(fields: [typeMachineId], references: [id], onDelete: Cascade)
|
typeMachine TypeMachine @relation(fields: [typeMachineId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
typePieceId String
|
typePieceId String
|
||||||
typePiece TypePiece @relation(fields: [typePieceId], references: [id])
|
typePiece ModelType @relation("ModelTypePieceRequirements", fields: [typePieceId], references: [id])
|
||||||
|
|
||||||
pieces Piece[]
|
pieces Piece[]
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { CustomFieldsModule } from './custom-fields/custom-fields.module';
|
|||||||
import { ConstructeursModule } from './constructeurs/constructeurs.module';
|
import { ConstructeursModule } from './constructeurs/constructeurs.module';
|
||||||
import { ProfilesModule } from './profiles/profiles.module';
|
import { ProfilesModule } from './profiles/profiles.module';
|
||||||
import { SessionModule } from './session/session.module';
|
import { SessionModule } from './session/session.module';
|
||||||
|
import { ModelTypeModule } from './model-type/model-type.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -30,6 +31,7 @@ import { SessionModule } from './session/session.module';
|
|||||||
ConstructeursModule,
|
ConstructeursModule,
|
||||||
ProfilesModule,
|
ProfilesModule,
|
||||||
SessionModule,
|
SessionModule,
|
||||||
|
ModelTypeModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ComposantsService } from './composants.service';
|
import { ComposantsService } from './composants.service';
|
||||||
import { CreateComposantDto, UpdateComposantDto } from '../shared/dto/composant.dto';
|
import {
|
||||||
|
CreateComposantDto,
|
||||||
|
UpdateComposantDto,
|
||||||
|
} from '../shared/dto/composant.dto';
|
||||||
|
|
||||||
@Controller('composants')
|
@Controller('composants')
|
||||||
export class ComposantsController {
|
export class ComposantsController {
|
||||||
@@ -32,7 +43,10 @@ export class ComposantsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
update(@Param('id') id: string, @Body() updateComposantDto: UpdateComposantDto) {
|
update(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateComposantDto: UpdateComposantDto,
|
||||||
|
) {
|
||||||
return this.composantsService.update(id, updateComposantDto);
|
return this.composantsService.update(id, updateComposantDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { ComposantsService } from './composants.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [ComposantsController],
|
controllers: [ComposantsController],
|
||||||
providers: [ComposantsService]
|
providers: [ComposantsService],
|
||||||
})
|
})
|
||||||
export class ComposantsModule {}
|
export class ComposantsModule {}
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ describe('ComposantsService', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [ComposantsService, { provide: PrismaService, useValue: prisma }],
|
providers: [
|
||||||
|
ComposantsService,
|
||||||
|
{ provide: PrismaService, useValue: prisma },
|
||||||
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<ComposantsService>(ComposantsService);
|
service = module.get<ComposantsService>(ComposantsService);
|
||||||
@@ -53,9 +56,9 @@ describe('ComposantsService', () => {
|
|||||||
await expect(service.create(dto)).resolves.toEqual(created);
|
await expect(service.create(dto)).resolves.toEqual(created);
|
||||||
|
|
||||||
expect(prisma.composant.create).toHaveBeenCalled();
|
expect(prisma.composant.create).toHaveBeenCalled();
|
||||||
expect(
|
expect(prisma.composant.create.mock.calls[0][0].data.typeComposantId).toBe(
|
||||||
prisma.composant.create.mock.calls[0][0].data.typeComposantId,
|
'type-comp-1',
|
||||||
).toBe('type-comp-1');
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refuse creation when requirement does not belong to machine skeleton', async () => {
|
it('should refuse creation when requirement does not belong to machine skeleton', async () => {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { CreateComposantDto, UpdateComposantDto } from '../shared/dto/composant.dto';
|
import {
|
||||||
|
CreateComposantDto,
|
||||||
|
UpdateComposantDto,
|
||||||
|
} from '../shared/dto/composant.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ComposantsService {
|
export class ComposantsService {
|
||||||
@@ -324,9 +327,9 @@ export class ComposantsService {
|
|||||||
async findHierarchy(machineId: string) {
|
async findHierarchy(machineId: string) {
|
||||||
// Récupérer tous les composants de premier niveau (sans parent)
|
// Récupérer tous les composants de premier niveau (sans parent)
|
||||||
const rootComposants = await this.prisma.composant.findMany({
|
const rootComposants = await this.prisma.composant.findMany({
|
||||||
where: {
|
where: {
|
||||||
machineId,
|
machineId,
|
||||||
parentComposantId: null
|
parentComposantId: null,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
typeComposant: true,
|
typeComposant: true,
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common'
|
import {
|
||||||
import { ConstructeursService } from './constructeurs.service'
|
Controller,
|
||||||
import { CreateConstructeurDto, UpdateConstructeurDto } from '../shared/dto/constructeur.dto'
|
Get,
|
||||||
|
Post,
|
||||||
|
Patch,
|
||||||
|
Delete,
|
||||||
|
Param,
|
||||||
|
Body,
|
||||||
|
Query,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ConstructeursService } from './constructeurs.service';
|
||||||
|
import {
|
||||||
|
CreateConstructeurDto,
|
||||||
|
UpdateConstructeurDto,
|
||||||
|
} from '../shared/dto/constructeur.dto';
|
||||||
|
|
||||||
@Controller('constructeurs')
|
@Controller('constructeurs')
|
||||||
export class ConstructeursController {
|
export class ConstructeursController {
|
||||||
@@ -8,26 +20,26 @@ export class ConstructeursController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() payload: CreateConstructeurDto) {
|
create(@Body() payload: CreateConstructeurDto) {
|
||||||
return this.constructeursService.create(payload)
|
return this.constructeursService.create(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
findAll(@Query('search') search?: string) {
|
findAll(@Query('search') search?: string) {
|
||||||
return this.constructeursService.findAll(search)
|
return this.constructeursService.findAll(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
findOne(@Param('id') id: string) {
|
findOne(@Param('id') id: string) {
|
||||||
return this.constructeursService.findOne(id)
|
return this.constructeursService.findOne(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
update(@Param('id') id: string, @Body() payload: UpdateConstructeurDto) {
|
update(@Param('id') id: string, @Body() payload: UpdateConstructeurDto) {
|
||||||
return this.constructeursService.update(id, payload)
|
return this.constructeursService.update(id, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
remove(@Param('id') id: string) {
|
remove(@Param('id') id: string) {
|
||||||
return this.constructeursService.remove(id)
|
return this.constructeursService.remove(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common';
|
||||||
import { ConstructeursService } from './constructeurs.service'
|
import { ConstructeursService } from './constructeurs.service';
|
||||||
import { ConstructeursController } from './constructeurs.controller'
|
import { ConstructeursController } from './constructeurs.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [ConstructeursController],
|
controllers: [ConstructeursController],
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service'
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { CreateConstructeurDto, UpdateConstructeurDto } from '../shared/dto/constructeur.dto'
|
import {
|
||||||
import { Prisma } from '@prisma/client'
|
CreateConstructeurDto,
|
||||||
|
UpdateConstructeurDto,
|
||||||
|
} from '../shared/dto/constructeur.dto';
|
||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ConstructeursService {
|
export class ConstructeursService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
private buildSearchWhere(search?: string): Prisma.ConstructeurWhereInput {
|
private buildSearchWhere(search?: string): Prisma.ConstructeurWhereInput {
|
||||||
if (!search) return {}
|
if (!search) return {};
|
||||||
const term = search.trim()
|
const term = search.trim();
|
||||||
if (!term) return {}
|
if (!term) return {};
|
||||||
return {
|
return {
|
||||||
OR: [
|
OR: [
|
||||||
{ name: { contains: term, mode: 'insensitive' } },
|
{ name: { contains: term, mode: 'insensitive' } },
|
||||||
{ email: { contains: term, mode: 'insensitive' } },
|
{ email: { contains: term, mode: 'insensitive' } },
|
||||||
{ phone: { contains: term, mode: 'insensitive' } },
|
{ phone: { contains: term, mode: 'insensitive' } },
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data: CreateConstructeurDto) {
|
async create(data: CreateConstructeurDto) {
|
||||||
@@ -28,20 +31,20 @@ export class ConstructeursService {
|
|||||||
email: data.email?.trim(),
|
email: data.email?.trim(),
|
||||||
phone: data.phone?.trim(),
|
phone: data.phone?.trim(),
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(search?: string) {
|
async findAll(search?: string) {
|
||||||
return this.prisma.constructeur.findMany({
|
return this.prisma.constructeur.findMany({
|
||||||
where: this.buildSearchWhere(search),
|
where: this.buildSearchWhere(search),
|
||||||
orderBy: { name: 'asc' },
|
orderBy: { name: 'asc' },
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(id: string) {
|
async findOne(id: string) {
|
||||||
return this.prisma.constructeur.findUnique({
|
return this.prisma.constructeur.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, data: UpdateConstructeurDto) {
|
async update(id: string, data: UpdateConstructeurDto) {
|
||||||
@@ -53,12 +56,12 @@ export class ConstructeursService {
|
|||||||
email: data.email?.trim(),
|
email: data.email?.trim(),
|
||||||
phone: data.phone?.trim(),
|
phone: data.phone?.trim(),
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string) {
|
async remove(id: string) {
|
||||||
return this.prisma.constructeur.delete({
|
return this.prisma.constructeur.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { CustomFieldsService } from './custom-fields.service';
|
import { CustomFieldsService } from './custom-fields.service';
|
||||||
import {
|
import {
|
||||||
CreateCustomFieldValueDto,
|
CreateCustomFieldValueDto,
|
||||||
@@ -12,8 +20,12 @@ export class CustomFieldsController {
|
|||||||
constructor(private readonly customFieldsService: CustomFieldsService) {}
|
constructor(private readonly customFieldsService: CustomFieldsService) {}
|
||||||
|
|
||||||
@Post('values')
|
@Post('values')
|
||||||
createCustomFieldValue(@Body() createCustomFieldValueDto: CreateCustomFieldValueDto) {
|
createCustomFieldValue(
|
||||||
return this.customFieldsService.createCustomFieldValue(createCustomFieldValueDto);
|
@Body() createCustomFieldValueDto: CreateCustomFieldValueDto,
|
||||||
|
) {
|
||||||
|
return this.customFieldsService.createCustomFieldValue(
|
||||||
|
createCustomFieldValueDto,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('values/:entityType/:entityId')
|
@Get('values/:entityType/:entityId')
|
||||||
@@ -34,7 +46,10 @@ export class CustomFieldsController {
|
|||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() updateCustomFieldValueDto: UpdateCustomFieldValueDto,
|
@Body() updateCustomFieldValueDto: UpdateCustomFieldValueDto,
|
||||||
) {
|
) {
|
||||||
return this.customFieldsService.updateCustomFieldValue(id, updateCustomFieldValueDto);
|
return this.customFieldsService.updateCustomFieldValue(
|
||||||
|
id,
|
||||||
|
updateCustomFieldValueDto,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete('values/:id')
|
@Delete('values/:id')
|
||||||
@@ -51,4 +66,4 @@ export class CustomFieldsController {
|
|||||||
body.value,
|
body.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ import { PrismaModule } from '../prisma/prisma.module';
|
|||||||
providers: [CustomFieldsService],
|
providers: [CustomFieldsService],
|
||||||
exports: [CustomFieldsService],
|
exports: [CustomFieldsService],
|
||||||
})
|
})
|
||||||
export class CustomFieldsModule {}
|
export class CustomFieldsModule {}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
import {
|
||||||
|
BadRequestException,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import {
|
import {
|
||||||
CreateCustomFieldValueDto,
|
CreateCustomFieldValueDto,
|
||||||
@@ -11,7 +15,9 @@ export class CustomFieldsService {
|
|||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
// Créer une valeur de champ personnalisé
|
// Créer une valeur de champ personnalisé
|
||||||
async createCustomFieldValue(createCustomFieldValueDto: CreateCustomFieldValueDto) {
|
async createCustomFieldValue(
|
||||||
|
createCustomFieldValueDto: CreateCustomFieldValueDto,
|
||||||
|
) {
|
||||||
return this.prisma.customFieldValue.create({
|
return this.prisma.customFieldValue.create({
|
||||||
data: createCustomFieldValueDto,
|
data: createCustomFieldValueDto,
|
||||||
include: {
|
include: {
|
||||||
@@ -30,11 +36,16 @@ export class CustomFieldsService {
|
|||||||
case CustomFieldEntityType.PIECE:
|
case CustomFieldEntityType.PIECE:
|
||||||
return 'pieceId' as const;
|
return 'pieceId' as const;
|
||||||
default:
|
default:
|
||||||
throw new BadRequestException('Type d\'entité de champ personnalisé invalide.');
|
throw new BadRequestException(
|
||||||
|
"Type d'entité de champ personnalisé invalide.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async resolveEntityContext(entityType: CustomFieldEntityType, entityId: string) {
|
private async resolveEntityContext(
|
||||||
|
entityType: CustomFieldEntityType,
|
||||||
|
entityId: string,
|
||||||
|
) {
|
||||||
switch (entityType) {
|
switch (entityType) {
|
||||||
case CustomFieldEntityType.MACHINE: {
|
case CustomFieldEntityType.MACHINE: {
|
||||||
const machine = await this.prisma.machine.findUnique({
|
const machine = await this.prisma.machine.findUnique({
|
||||||
@@ -103,7 +114,9 @@ export class CustomFieldsService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new BadRequestException('Type d\'entité de champ personnalisé invalide.');
|
throw new BadRequestException(
|
||||||
|
"Type d'entité de champ personnalisé invalide.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +148,10 @@ export class CustomFieldsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mettre à jour une valeur de champ personnalisé
|
// Mettre à jour une valeur de champ personnalisé
|
||||||
async updateCustomFieldValue(id: string, updateCustomFieldValueDto: UpdateCustomFieldValueDto) {
|
async updateCustomFieldValue(
|
||||||
|
id: string,
|
||||||
|
updateCustomFieldValueDto: UpdateCustomFieldValueDto,
|
||||||
|
) {
|
||||||
return this.prisma.customFieldValue.update({
|
return this.prisma.customFieldValue.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: updateCustomFieldValueDto,
|
data: updateCustomFieldValueDto,
|
||||||
@@ -159,10 +175,8 @@ export class CustomFieldsService {
|
|||||||
entityId: string,
|
entityId: string,
|
||||||
value: string,
|
value: string,
|
||||||
) {
|
) {
|
||||||
const { typeId, customFieldTypeField, valueKey } = await this.resolveEntityContext(
|
const { typeId, customFieldTypeField, valueKey } =
|
||||||
entityType,
|
await this.resolveEntityContext(entityType, entityId);
|
||||||
entityId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const allowedCustomField = await this.prisma.customField.findFirst({
|
const allowedCustomField = await this.prisma.customField.findFirst({
|
||||||
where: {
|
where: {
|
||||||
@@ -173,7 +187,7 @@ export class CustomFieldsService {
|
|||||||
|
|
||||||
if (!allowedCustomField) {
|
if (!allowedCustomField) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
'Le champ personnalisé n\'est pas autorisé pour cette entité.',
|
"Le champ personnalisé n'est pas autorisé pour cette entité.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { DocumentsService } from './documents.service';
|
import { DocumentsService } from './documents.service';
|
||||||
import { CreateDocumentDto, UpdateDocumentDto } from '../shared/dto/document.dto';
|
import {
|
||||||
|
CreateDocumentDto,
|
||||||
|
UpdateDocumentDto,
|
||||||
|
} from '../shared/dto/document.dto';
|
||||||
|
|
||||||
@Controller('documents')
|
@Controller('documents')
|
||||||
export class DocumentsController {
|
export class DocumentsController {
|
||||||
@@ -42,7 +53,10 @@ export class DocumentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
update(@Param('id') id: string, @Body() updateDocumentDto: UpdateDocumentDto) {
|
update(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateDocumentDto: UpdateDocumentDto,
|
||||||
|
) {
|
||||||
return this.documentsService.update(id, updateDocumentDto);
|
return this.documentsService.update(id, updateDocumentDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { DocumentsService } from './documents.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [DocumentsController],
|
controllers: [DocumentsController],
|
||||||
providers: [DocumentsService]
|
providers: [DocumentsService],
|
||||||
})
|
})
|
||||||
export class DocumentsModule {}
|
export class DocumentsModule {}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { CreateDocumentDto, UpdateDocumentDto } from '../shared/dto/document.dto';
|
import {
|
||||||
|
CreateDocumentDto,
|
||||||
|
UpdateDocumentDto,
|
||||||
|
} from '../shared/dto/document.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DocumentsService {
|
export class DocumentsService {
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { MachinesService } from './machines.service';
|
import { MachinesService } from './machines.service';
|
||||||
import {
|
import {
|
||||||
CreateMachineDto,
|
CreateMachineDto,
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { MachinesService } from './machines.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [MachinesController],
|
controllers: [MachinesController],
|
||||||
providers: [MachinesService]
|
providers: [MachinesService],
|
||||||
})
|
})
|
||||||
export class MachinesModule {}
|
export class MachinesModule {}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ModelCategory } from '@prisma/client';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import {
|
import {
|
||||||
CreateMachineDto,
|
CreateMachineDto,
|
||||||
@@ -90,6 +91,36 @@ const MACHINE_DEFAULT_INCLUDE = {
|
|||||||
export class MachinesService {
|
export class MachinesService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private slugifyName(name: string): string {
|
||||||
|
return name
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
.replace(/-+/g, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateUniqueComponentTypeCode(
|
||||||
|
prisma: any,
|
||||||
|
name: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const base = this.slugifyName(name) || 'type';
|
||||||
|
let candidate = base;
|
||||||
|
let suffix = 1;
|
||||||
|
|
||||||
|
while (
|
||||||
|
await prisma.modelType.findUnique({
|
||||||
|
where: { code: candidate },
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
candidate = `${base}-${suffix++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
private async getTypeMachineConfiguration(typeMachineId: string) {
|
private async getTypeMachineConfiguration(typeMachineId: string) {
|
||||||
const typeMachine = await this.prisma.typeMachine.findUnique({
|
const typeMachine = await this.prisma.typeMachine.findUnique({
|
||||||
where: { id: typeMachineId },
|
where: { id: typeMachineId },
|
||||||
@@ -108,25 +139,40 @@ export class MachinesService {
|
|||||||
componentSelections: MachineComponentSelectionDto[],
|
componentSelections: MachineComponentSelectionDto[],
|
||||||
pieceSelections: MachinePieceSelectionDto[],
|
pieceSelections: MachinePieceSelectionDto[],
|
||||||
) {
|
) {
|
||||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
const componentRequirements = (
|
||||||
? typeMachine.componentRequirements
|
Array.isArray(typeMachine.componentRequirements)
|
||||||
: []) as any[];
|
? typeMachine.componentRequirements
|
||||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
: []
|
||||||
? typeMachine.pieceRequirements
|
) as any[];
|
||||||
: []) as any[];
|
const pieceRequirements = (
|
||||||
|
Array.isArray(typeMachine.pieceRequirements)
|
||||||
|
? typeMachine.pieceRequirements
|
||||||
|
: []
|
||||||
|
) as any[];
|
||||||
|
|
||||||
const componentRequirementMap = new Map(
|
const componentRequirementMap = new Map(
|
||||||
componentRequirements.map((requirement: any) => [requirement.id, requirement]),
|
componentRequirements.map((requirement: any) => [
|
||||||
|
requirement.id,
|
||||||
|
requirement,
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
const pieceRequirementMap = new Map(
|
const pieceRequirementMap = new Map(
|
||||||
pieceRequirements.map((requirement: any) => [requirement.id, requirement]),
|
pieceRequirements.map((requirement: any) => [
|
||||||
|
requirement.id,
|
||||||
|
requirement,
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const componentSelectionMap = new Map<string, MachineComponentSelectionDto[]>();
|
const componentSelectionMap = new Map<
|
||||||
|
string,
|
||||||
|
MachineComponentSelectionDto[]
|
||||||
|
>();
|
||||||
for (const selection of componentSelections) {
|
for (const selection of componentSelections) {
|
||||||
const requirement = componentRequirementMap.get(selection.requirementId);
|
const requirement = componentRequirementMap.get(selection.requirementId);
|
||||||
if (!requirement) {
|
if (!requirement) {
|
||||||
throw new Error(`Sélection de composant invalide: requirementId=${selection.requirementId}`);
|
throw new Error(
|
||||||
|
`Sélection de composant invalide: requirementId=${selection.requirementId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!componentSelectionMap.has(requirement.id)) {
|
if (!componentSelectionMap.has(requirement.id)) {
|
||||||
componentSelectionMap.set(requirement.id, []);
|
componentSelectionMap.set(requirement.id, []);
|
||||||
@@ -138,7 +184,16 @@ export class MachinesService {
|
|||||||
for (const selection of pieceSelections) {
|
for (const selection of pieceSelections) {
|
||||||
const requirement = pieceRequirementMap.get(selection.requirementId);
|
const requirement = pieceRequirementMap.get(selection.requirementId);
|
||||||
if (!requirement) {
|
if (!requirement) {
|
||||||
throw new Error(`Sélection de pièce invalide: requirementId=${selection.requirementId}`);
|
throw new Error(
|
||||||
|
`Sélection de pièce invalide: requirementId=${selection.requirementId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!selection.pieceModelId) {
|
||||||
|
throw new Error(
|
||||||
|
`Le groupe de pièces "${
|
||||||
|
requirement.label || requirement.typePiece?.name || requirement.id
|
||||||
|
}" nécessite la sélection d'un modèle de pièce.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!pieceSelectionMap.has(requirement.id)) {
|
if (!pieceSelectionMap.has(requirement.id)) {
|
||||||
pieceSelectionMap.set(requirement.id, []);
|
pieceSelectionMap.set(requirement.id, []);
|
||||||
@@ -147,24 +202,36 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const componentModelIds = Array.from(
|
const componentModelIds = Array.from(
|
||||||
new Set(componentSelections.map((selection) => selection.componentModelId).filter(Boolean)),
|
new Set(
|
||||||
|
componentSelections
|
||||||
|
.map((selection) => selection.componentModelId)
|
||||||
|
.filter(Boolean),
|
||||||
|
),
|
||||||
) as string[];
|
) as string[];
|
||||||
const componentModels = componentModelIds.length
|
const componentModels = componentModelIds.length
|
||||||
? await this.prisma.composantModel.findMany({
|
? await this.prisma.composantModel.findMany({
|
||||||
where: { id: { in: componentModelIds } },
|
where: { id: { in: componentModelIds } },
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
const componentModelMap = new Map(componentModels.map((model) => [model.id, model]));
|
const componentModelMap = new Map(
|
||||||
|
componentModels.map((model) => [model.id, model]),
|
||||||
|
);
|
||||||
|
|
||||||
const pieceModelIds = Array.from(
|
const pieceModelIds = Array.from(
|
||||||
new Set(pieceSelections.map((selection) => selection.pieceModelId).filter(Boolean)),
|
new Set(
|
||||||
|
pieceSelections
|
||||||
|
.map((selection) => selection.pieceModelId)
|
||||||
|
.filter(Boolean),
|
||||||
|
),
|
||||||
) as string[];
|
) 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 } },
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
const pieceModelMap = new Map(pieceModels.map((model) => [model.id, model]));
|
const pieceModelMap = new Map(
|
||||||
|
pieceModels.map((model) => [model.id, model]),
|
||||||
|
);
|
||||||
|
|
||||||
for (const requirement of componentRequirements) {
|
for (const requirement of componentRequirements) {
|
||||||
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
||||||
@@ -184,7 +251,9 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!requirement.allowNewModels) {
|
if (!requirement.allowNewModels) {
|
||||||
const missingModel = selections.find((selection) => !selection.componentModelId);
|
const missingModel = selections.find(
|
||||||
|
(selection) => !selection.componentModelId,
|
||||||
|
);
|
||||||
if (missingModel) {
|
if (missingModel) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Le groupe de composants "${requirement.label || requirement.typeComposant?.name || requirement.id}" n'autorise que la sélection de modèles existants.`,
|
`Le groupe de composants "${requirement.label || requirement.typeComposant?.name || requirement.id}" n'autorise que la sélection de modèles existants.`,
|
||||||
@@ -210,14 +279,6 @@ export class MachinesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!requirement.allowNewModels) {
|
|
||||||
const missingModel = selections.find((selection) => !selection.pieceModelId);
|
|
||||||
if (missingModel) {
|
|
||||||
throw new Error(
|
|
||||||
`Le groupe de pièces "${requirement.label || requirement.typePiece?.name || requirement.id}" n'autorise que la sélection de modèles existants.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const selection of componentSelections) {
|
for (const selection of componentSelections) {
|
||||||
@@ -226,11 +287,15 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
const model = componentModelMap.get(selection.componentModelId);
|
const model = componentModelMap.get(selection.componentModelId);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new Error(`Modèle de composant introuvable: ${selection.componentModelId}`);
|
throw new Error(
|
||||||
|
`Modèle de composant introuvable: ${selection.componentModelId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const requirement = componentRequirementMap.get(selection.requirementId);
|
const requirement = componentRequirementMap.get(selection.requirementId);
|
||||||
if (!requirement) {
|
if (!requirement) {
|
||||||
throw new Error(`Requirement de composant introuvable: ${selection.requirementId}`);
|
throw new Error(
|
||||||
|
`Requirement de composant introuvable: ${selection.requirementId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (model.typeComposantId !== requirement.typeComposantId) {
|
if (model.typeComposantId !== requirement.typeComposantId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -240,16 +305,17 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const selection of pieceSelections) {
|
for (const selection of pieceSelections) {
|
||||||
if (!selection.pieceModelId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const model = pieceModelMap.get(selection.pieceModelId);
|
const model = pieceModelMap.get(selection.pieceModelId);
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new Error(`Modèle de pièce introuvable: ${selection.pieceModelId}`);
|
throw new Error(
|
||||||
|
`Modèle de pièce introuvable: ${selection.pieceModelId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const requirement = pieceRequirementMap.get(selection.requirementId);
|
const requirement = pieceRequirementMap.get(selection.requirementId);
|
||||||
if (!requirement) {
|
if (!requirement) {
|
||||||
throw new Error(`Requirement de pièce introuvable: ${selection.requirementId}`);
|
throw new Error(
|
||||||
|
`Requirement de pièce introuvable: ${selection.requirementId}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (model.typePieceId !== requirement.typePieceId) {
|
if (model.typePieceId !== requirement.typePieceId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -274,24 +340,36 @@ export class MachinesService {
|
|||||||
} = createMachineDto;
|
} = createMachineDto;
|
||||||
|
|
||||||
if (!machineData.typeMachineId) {
|
if (!machineData.typeMachineId) {
|
||||||
throw new Error('typeMachineId est requis pour créer une machine à partir d\'un squelette.');
|
throw new Error(
|
||||||
|
"typeMachineId est requis pour créer une machine à partir d'un squelette.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeMachine = await this.getTypeMachineConfiguration(machineData.typeMachineId);
|
const typeMachine = await this.getTypeMachineConfiguration(
|
||||||
|
machineData.typeMachineId,
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
componentSelectionMap,
|
componentSelectionMap,
|
||||||
pieceSelectionMap,
|
pieceSelectionMap,
|
||||||
componentModelMap,
|
componentModelMap,
|
||||||
pieceModelMap,
|
pieceModelMap,
|
||||||
} = await this.buildConfigurationContext(typeMachine, componentSelections, pieceSelections);
|
} = await this.buildConfigurationContext(
|
||||||
|
typeMachine,
|
||||||
|
componentSelections,
|
||||||
|
pieceSelections,
|
||||||
|
);
|
||||||
|
|
||||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
const componentRequirements = (
|
||||||
? typeMachine.componentRequirements
|
Array.isArray(typeMachine.componentRequirements)
|
||||||
: []) as any[];
|
? typeMachine.componentRequirements
|
||||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
: []
|
||||||
? typeMachine.pieceRequirements
|
) as any[];
|
||||||
: []) as any[];
|
const pieceRequirements = (
|
||||||
|
Array.isArray(typeMachine.pieceRequirements)
|
||||||
|
? typeMachine.pieceRequirements
|
||||||
|
: []
|
||||||
|
) as any[];
|
||||||
|
|
||||||
return this.prisma.$transaction(async (prisma) => {
|
return this.prisma.$transaction(async (prisma) => {
|
||||||
const machine = await prisma.machine.create({
|
const machine = await prisma.machine.create({
|
||||||
@@ -307,15 +385,27 @@ export class MachinesService {
|
|||||||
for (const requirement of componentRequirements) {
|
for (const requirement of componentRequirements) {
|
||||||
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
const model = selection.componentModelId ? componentModelMap.get(selection.componentModelId) : undefined;
|
const model = selection.componentModelId
|
||||||
const definition = this.normalizeComponentSelection(selection, requirement, model);
|
? componentModelMap.get(selection.componentModelId)
|
||||||
await this.createComponentsFromType(prisma, machine.id, [definition]);
|
: undefined;
|
||||||
|
const definition = this.normalizeComponentSelection(
|
||||||
|
selection,
|
||||||
|
requirement,
|
||||||
|
model,
|
||||||
|
);
|
||||||
|
await this.createComponentsFromType(prisma, machine.id, [
|
||||||
|
definition,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const legacyComponents = (typeMachine as any).components;
|
const legacyComponents = (typeMachine as any).components;
|
||||||
if (legacyComponents) {
|
if (legacyComponents) {
|
||||||
await this.createComponentsFromType(prisma, machine.id, legacyComponents);
|
await this.createComponentsFromType(
|
||||||
|
prisma,
|
||||||
|
machine.id,
|
||||||
|
legacyComponents,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,20 +413,36 @@ export class MachinesService {
|
|||||||
for (const requirement of pieceRequirements) {
|
for (const requirement of pieceRequirements) {
|
||||||
const selections = pieceSelectionMap.get(requirement.id) ?? [];
|
const selections = pieceSelectionMap.get(requirement.id) ?? [];
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
const model = selection.pieceModelId ? pieceModelMap.get(selection.pieceModelId) : undefined;
|
const model = selection.pieceModelId
|
||||||
const definition = this.normalizePieceSelection(selection, requirement, model);
|
? pieceModelMap.get(selection.pieceModelId)
|
||||||
await this.createMachinePiecesFromType(prisma, machine.id, [definition]);
|
: undefined;
|
||||||
|
const definition = this.normalizePieceSelection(
|
||||||
|
selection,
|
||||||
|
requirement,
|
||||||
|
model,
|
||||||
|
);
|
||||||
|
await this.createMachinePiecesFromType(prisma, machine.id, [
|
||||||
|
definition,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const legacyPieces = (typeMachine as any).machinePieces;
|
const legacyPieces = (typeMachine as any).machinePieces;
|
||||||
if (legacyPieces) {
|
if (legacyPieces) {
|
||||||
await this.createMachinePiecesFromType(prisma, machine.id, legacyPieces);
|
await this.createMachinePiecesFromType(
|
||||||
|
prisma,
|
||||||
|
machine.id,
|
||||||
|
legacyPieces,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeMachine.customFields && typeMachine.customFields.length > 0) {
|
if (typeMachine.customFields && typeMachine.customFields.length > 0) {
|
||||||
await this.createMachineCustomFieldsFromType(prisma, machine.id, typeMachine.customFields);
|
await this.createMachineCustomFieldsFromType(
|
||||||
|
prisma,
|
||||||
|
machine.id,
|
||||||
|
typeMachine.customFields,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return prisma.machine.findUnique({
|
return prisma.machine.findUnique({
|
||||||
@@ -371,28 +477,43 @@ export class MachinesService {
|
|||||||
requirement: any,
|
requirement: any,
|
||||||
model?: any,
|
model?: any,
|
||||||
): any {
|
): any {
|
||||||
const baseDefinition = selection.definition ?? (model?.structure ?? {});
|
const baseDefinition = selection.definition ?? model?.structure ?? {};
|
||||||
const definition = this.cloneStructure(baseDefinition);
|
const definition = this.cloneStructure(baseDefinition);
|
||||||
const prepared: any = definition && typeof definition === 'object' && !Array.isArray(definition) ? definition : {};
|
const prepared: any =
|
||||||
|
definition && typeof definition === 'object' && !Array.isArray(definition)
|
||||||
|
? definition
|
||||||
|
: {};
|
||||||
|
|
||||||
prepared.name = prepared.name || model?.name || requirement?.typeComposant?.name || 'Composant';
|
prepared.name =
|
||||||
prepared.reference = prepared.reference ?? model?.structure?.reference ?? '';
|
prepared.name ||
|
||||||
prepared.emplacement = prepared.emplacement ?? model?.structure?.emplacement ?? '';
|
model?.name ||
|
||||||
|
requirement?.typeComposant?.name ||
|
||||||
|
'Composant';
|
||||||
|
prepared.reference =
|
||||||
|
prepared.reference ?? model?.structure?.reference ?? '';
|
||||||
|
prepared.emplacement =
|
||||||
|
prepared.emplacement ?? model?.structure?.emplacement ?? '';
|
||||||
prepared.prix = prepared.prix ?? model?.structure?.prix ?? null;
|
prepared.prix = prepared.prix ?? model?.structure?.prix ?? null;
|
||||||
|
|
||||||
prepared.customFields = Array.isArray(prepared.customFields) ? prepared.customFields : [];
|
prepared.customFields = Array.isArray(prepared.customFields)
|
||||||
|
? prepared.customFields
|
||||||
|
: [];
|
||||||
prepared.pieces = Array.isArray(prepared.pieces)
|
prepared.pieces = Array.isArray(prepared.pieces)
|
||||||
? prepared.pieces
|
? prepared.pieces
|
||||||
: prepared.pieces
|
: prepared.pieces
|
||||||
? [prepared.pieces]
|
? [prepared.pieces]
|
||||||
: [];
|
: [];
|
||||||
prepared.subComponents = Array.isArray(prepared.subComponents)
|
prepared.subComponents = Array.isArray(prepared.subComponents)
|
||||||
? prepared.subComponents
|
? prepared.subComponents
|
||||||
: prepared.subComponents
|
: prepared.subComponents
|
||||||
? [prepared.subComponents]
|
? [prepared.subComponents]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
prepared.typeComposantId = prepared.typeComposantId || requirement?.typeComposantId || model?.typeComposantId || null;
|
prepared.typeComposantId =
|
||||||
|
prepared.typeComposantId ||
|
||||||
|
requirement?.typeComposantId ||
|
||||||
|
model?.typeComposantId ||
|
||||||
|
null;
|
||||||
prepared.__componentModelId = selection.componentModelId ?? null;
|
prepared.__componentModelId = selection.componentModelId ?? null;
|
||||||
prepared.__requirementId = requirement?.id ?? null;
|
prepared.__requirementId = requirement?.id ?? null;
|
||||||
|
|
||||||
@@ -404,43 +525,80 @@ export class MachinesService {
|
|||||||
requirement: any,
|
requirement: any,
|
||||||
model?: any,
|
model?: any,
|
||||||
): any {
|
): any {
|
||||||
const baseDefinition = selection.definition ?? (model?.structure ?? {});
|
if (!model) {
|
||||||
const definition = this.cloneStructure(baseDefinition);
|
throw new Error(
|
||||||
const prepared: any = definition && typeof definition === 'object' && !Array.isArray(definition) ? definition : {};
|
`Modèle de pièce introuvable: ${selection.pieceModelId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
prepared.name = prepared.name || model?.name || requirement?.typePiece?.name || 'Pièce';
|
const baseDefinition = model.structure ?? {};
|
||||||
prepared.customFields = Array.isArray(prepared.customFields) ? prepared.customFields : [];
|
const definition = this.cloneStructure(baseDefinition);
|
||||||
prepared.typePieceId = prepared.typePieceId || requirement?.typePieceId || model?.typePieceId || null;
|
const prepared: any =
|
||||||
prepared.__pieceModelId = selection.pieceModelId ?? null;
|
definition && typeof definition === 'object' && !Array.isArray(definition)
|
||||||
|
? definition
|
||||||
|
: {};
|
||||||
|
|
||||||
|
prepared.name = prepared.name || model.name || 'Pièce';
|
||||||
|
prepared.customFields = Array.isArray(prepared.customFields)
|
||||||
|
? prepared.customFields
|
||||||
|
: [];
|
||||||
|
prepared.typePieceId =
|
||||||
|
prepared.typePieceId ||
|
||||||
|
model.typePieceId ||
|
||||||
|
requirement?.typePieceId ||
|
||||||
|
null;
|
||||||
|
prepared.__pieceModelId = selection.pieceModelId;
|
||||||
prepared.__requirementId = requirement?.id ?? null;
|
prepared.__requirementId = requirement?.id ?? null;
|
||||||
|
|
||||||
return prepared;
|
return prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createComponentsFromType(prisma: any, machineId: string, components: any[], parentComposantId?: string) {
|
private async createComponentsFromType(
|
||||||
|
prisma: any,
|
||||||
|
machineId: string,
|
||||||
|
components: any[],
|
||||||
|
parentComposantId?: string,
|
||||||
|
) {
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
if (!component || !component.name) continue;
|
if (!component || !component.name) continue;
|
||||||
|
|
||||||
const customFields = Array.isArray(component.customFields) ? component.customFields : [];
|
const customFields = Array.isArray(component.customFields)
|
||||||
const componentPieces = Array.isArray(component.pieces) ? component.pieces : [];
|
? component.customFields
|
||||||
const subComponents = Array.isArray(component.subComponents) ? component.subComponents : [];
|
: [];
|
||||||
|
const componentPieces = Array.isArray(component.pieces)
|
||||||
|
? component.pieces
|
||||||
|
: [];
|
||||||
|
const subComponents = Array.isArray(component.subComponents)
|
||||||
|
? component.subComponents
|
||||||
|
: [];
|
||||||
|
|
||||||
const componentModelId = component.__componentModelId ?? null;
|
const componentModelId = component.__componentModelId ?? null;
|
||||||
const requirementId = component.__requirementId ?? null;
|
const requirementId = component.__requirementId ?? null;
|
||||||
const providedTypeComposantId = component.typeComposantId
|
const providedTypeComposantId =
|
||||||
?? (component.typeComposant && component.typeComposant.id ? component.typeComposant.id : null);
|
component.typeComposantId ??
|
||||||
|
(component.typeComposant && component.typeComposant.id
|
||||||
|
? component.typeComposant.id
|
||||||
|
: null);
|
||||||
|
|
||||||
let typeComposantId: string | null = providedTypeComposantId ?? null;
|
let typeComposantId: string | null = providedTypeComposantId ?? null;
|
||||||
|
|
||||||
if (!typeComposantId && customFields.length > 0) {
|
if (!typeComposantId && customFields.length > 0) {
|
||||||
let typeComposant = await prisma.typeComposant.findFirst({
|
let typeComposant = await prisma.modelType.findFirst({
|
||||||
where: { name: component.name },
|
where: {
|
||||||
|
name: component.name,
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!typeComposant) {
|
if (!typeComposant) {
|
||||||
typeComposant = await prisma.typeComposant.create({
|
typeComposant = await prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
name: component.name,
|
name: component.name,
|
||||||
|
code: await this.generateUniqueComponentTypeCode(
|
||||||
|
prisma,
|
||||||
|
component.name,
|
||||||
|
),
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
description: component.description || '',
|
description: component.description || '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -466,7 +624,10 @@ export class MachinesService {
|
|||||||
data: {
|
data: {
|
||||||
name: component.name,
|
name: component.name,
|
||||||
reference: component.reference || '',
|
reference: component.reference || '',
|
||||||
constructeurId: await this.resolveConstructeurId(prisma, component.constructeur),
|
constructeurId: await this.resolveConstructeurId(
|
||||||
|
prisma,
|
||||||
|
component.constructeur,
|
||||||
|
),
|
||||||
emplacement: component.emplacement || '',
|
emplacement: component.emplacement || '',
|
||||||
prix: component.prix ?? null,
|
prix: component.prix ?? null,
|
||||||
machineId,
|
machineId,
|
||||||
@@ -483,7 +644,9 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const customField of typeCustomFields) {
|
for (const customField of typeCustomFields) {
|
||||||
const defaultValue = customFields.find((cf) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
customFields.find((cf) => cf.name === customField.name)
|
||||||
|
?.defaultValue || '';
|
||||||
await prisma.customFieldValue.create({
|
await prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
@@ -497,11 +660,14 @@ export class MachinesService {
|
|||||||
for (const piece of componentPieces) {
|
for (const piece of componentPieces) {
|
||||||
if (!piece || !piece.name) continue;
|
if (!piece || !piece.name) continue;
|
||||||
|
|
||||||
const pieceCustomFields = Array.isArray(piece.customFields) ? piece.customFields : [];
|
const pieceCustomFields = Array.isArray(piece.customFields)
|
||||||
|
? piece.customFields
|
||||||
|
: [];
|
||||||
const pieceModelId = piece.__pieceModelId ?? null;
|
const pieceModelId = piece.__pieceModelId ?? null;
|
||||||
const pieceRequirementId = piece.__requirementId ?? null;
|
const pieceRequirementId = piece.__requirementId ?? null;
|
||||||
const providedTypePieceId = piece.typePieceId
|
const providedTypePieceId =
|
||||||
?? (piece.typePiece && piece.typePiece.id ? piece.typePiece.id : null);
|
piece.typePieceId ??
|
||||||
|
(piece.typePiece && piece.typePiece.id ? piece.typePiece.id : null);
|
||||||
|
|
||||||
let typePieceId: string | null = providedTypePieceId ?? null;
|
let typePieceId: string | null = providedTypePieceId ?? null;
|
||||||
|
|
||||||
@@ -539,7 +705,10 @@ export class MachinesService {
|
|||||||
data: {
|
data: {
|
||||||
name: piece.name,
|
name: piece.name,
|
||||||
reference: piece.reference || '',
|
reference: piece.reference || '',
|
||||||
constructeurId: await this.resolveConstructeurId(prisma, piece.constructeur),
|
constructeurId: await this.resolveConstructeurId(
|
||||||
|
prisma,
|
||||||
|
piece.constructeur,
|
||||||
|
),
|
||||||
emplacement: piece.emplacement || '',
|
emplacement: piece.emplacement || '',
|
||||||
prix: piece.prix ?? null,
|
prix: piece.prix ?? null,
|
||||||
composantId: createdComposant.id,
|
composantId: createdComposant.id,
|
||||||
@@ -555,7 +724,9 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const customField of typePieceCustomFields) {
|
for (const customField of typePieceCustomFields) {
|
||||||
const defaultValue = pieceCustomFields.find((cf) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
pieceCustomFields.find((cf) => cf.name === customField.name)
|
||||||
|
?.defaultValue || '';
|
||||||
await prisma.customFieldValue.create({
|
await prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
@@ -568,20 +739,32 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subComponents.length > 0) {
|
if (subComponents.length > 0) {
|
||||||
await this.createComponentsFromType(prisma, machineId, subComponents, createdComposant.id);
|
await this.createComponentsFromType(
|
||||||
|
prisma,
|
||||||
|
machineId,
|
||||||
|
subComponents,
|
||||||
|
createdComposant.id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createMachinePiecesFromType(prisma: any, machineId: string, machinePieces: any[]) {
|
private async createMachinePiecesFromType(
|
||||||
|
prisma: any,
|
||||||
|
machineId: string,
|
||||||
|
machinePieces: any[],
|
||||||
|
) {
|
||||||
for (const piece of machinePieces) {
|
for (const piece of machinePieces) {
|
||||||
if (!piece || !piece.name) continue;
|
if (!piece || !piece.name) continue;
|
||||||
|
|
||||||
const customFields = Array.isArray(piece.customFields) ? piece.customFields : [];
|
const customFields = Array.isArray(piece.customFields)
|
||||||
|
? piece.customFields
|
||||||
|
: [];
|
||||||
const pieceModelId = piece.__pieceModelId ?? null;
|
const pieceModelId = piece.__pieceModelId ?? null;
|
||||||
const requirementId = piece.__requirementId ?? null;
|
const requirementId = piece.__requirementId ?? null;
|
||||||
const providedTypePieceId = piece.typePieceId
|
const providedTypePieceId =
|
||||||
?? (piece.typePiece && piece.typePiece.id ? piece.typePiece.id : null);
|
piece.typePieceId ??
|
||||||
|
(piece.typePiece && piece.typePiece.id ? piece.typePiece.id : null);
|
||||||
|
|
||||||
let typePieceId: string | null = providedTypePieceId ?? null;
|
let typePieceId: string | null = providedTypePieceId ?? null;
|
||||||
|
|
||||||
@@ -619,7 +802,10 @@ export class MachinesService {
|
|||||||
data: {
|
data: {
|
||||||
name: piece.name,
|
name: piece.name,
|
||||||
reference: piece.reference || '',
|
reference: piece.reference || '',
|
||||||
constructeurId: await this.resolveConstructeurId(prisma, piece.constructeur),
|
constructeurId: await this.resolveConstructeurId(
|
||||||
|
prisma,
|
||||||
|
piece.constructeur,
|
||||||
|
),
|
||||||
emplacement: piece.emplacement || '',
|
emplacement: piece.emplacement || '',
|
||||||
prix: piece.prix ?? null,
|
prix: piece.prix ?? null,
|
||||||
machineId,
|
machineId,
|
||||||
@@ -635,7 +821,9 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const customField of typePieceCustomFields) {
|
for (const customField of typePieceCustomFields) {
|
||||||
const defaultValue = customFields.find((cf) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
customFields.find((cf) => cf.name === customField.name)
|
||||||
|
?.defaultValue || '';
|
||||||
await prisma.customFieldValue.create({
|
await prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
@@ -669,10 +857,14 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createMachineCustomFieldsFromType(prisma: any, machineId: string, machineCustomFields: any[]) {
|
private async createMachineCustomFieldsFromType(
|
||||||
|
prisma: any,
|
||||||
|
machineId: string,
|
||||||
|
machineCustomFields: any[],
|
||||||
|
) {
|
||||||
for (const customField of machineCustomFields) {
|
for (const customField of machineCustomFields) {
|
||||||
if (!customField || !customField.name) continue;
|
if (!customField || !customField.name) continue;
|
||||||
|
|
||||||
// Créer le champ personnalisé pour la machine
|
// Créer le champ personnalisé pour la machine
|
||||||
const createdCustomField = await prisma.customField.create({
|
const createdCustomField = await prisma.customField.create({
|
||||||
data: {
|
data: {
|
||||||
@@ -710,10 +902,8 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reconfigure(id: string, reconfigureMachineDto: ReconfigureMachineDto) {
|
async reconfigure(id: string, reconfigureMachineDto: ReconfigureMachineDto) {
|
||||||
const {
|
const { componentSelections = [], pieceSelections = [] } =
|
||||||
componentSelections = [],
|
reconfigureMachineDto;
|
||||||
pieceSelections = [],
|
|
||||||
} = reconfigureMachineDto;
|
|
||||||
|
|
||||||
const machine = await this.prisma.machine.findUnique({
|
const machine = await this.prisma.machine.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
@@ -729,7 +919,9 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!machine.typeMachineId || !machine.typeMachine) {
|
if (!machine.typeMachineId || !machine.typeMachine) {
|
||||||
throw new Error('Impossible de reconfigurer une machine sans type de machine associé.');
|
throw new Error(
|
||||||
|
'Impossible de reconfigurer une machine sans type de machine associé.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeMachine = machine.typeMachine;
|
const typeMachine = machine.typeMachine;
|
||||||
@@ -739,14 +931,22 @@ export class MachinesService {
|
|||||||
pieceSelectionMap,
|
pieceSelectionMap,
|
||||||
componentModelMap,
|
componentModelMap,
|
||||||
pieceModelMap,
|
pieceModelMap,
|
||||||
} = await this.buildConfigurationContext(typeMachine, componentSelections, pieceSelections);
|
} = await this.buildConfigurationContext(
|
||||||
|
typeMachine,
|
||||||
|
componentSelections,
|
||||||
|
pieceSelections,
|
||||||
|
);
|
||||||
|
|
||||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
const componentRequirements = (
|
||||||
? typeMachine.componentRequirements
|
Array.isArray(typeMachine.componentRequirements)
|
||||||
: []) as any[];
|
? typeMachine.componentRequirements
|
||||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
: []
|
||||||
? typeMachine.pieceRequirements
|
) as any[];
|
||||||
: []) as any[];
|
const pieceRequirements = (
|
||||||
|
Array.isArray(typeMachine.pieceRequirements)
|
||||||
|
? typeMachine.pieceRequirements
|
||||||
|
: []
|
||||||
|
) as any[];
|
||||||
|
|
||||||
return this.prisma.$transaction(async (prisma) => {
|
return this.prisma.$transaction(async (prisma) => {
|
||||||
await prisma.customFieldValue.deleteMany({
|
await prisma.customFieldValue.deleteMany({
|
||||||
@@ -797,7 +997,11 @@ export class MachinesService {
|
|||||||
const model = selection.componentModelId
|
const model = selection.componentModelId
|
||||||
? componentModelMap.get(selection.componentModelId)
|
? componentModelMap.get(selection.componentModelId)
|
||||||
: undefined;
|
: undefined;
|
||||||
const definition = this.normalizeComponentSelection(selection, requirement, model);
|
const definition = this.normalizeComponentSelection(
|
||||||
|
selection,
|
||||||
|
requirement,
|
||||||
|
model,
|
||||||
|
);
|
||||||
await this.createComponentsFromType(prisma, id, [definition]);
|
await this.createComponentsFromType(prisma, id, [definition]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,7 +1019,11 @@ export class MachinesService {
|
|||||||
const model = selection.pieceModelId
|
const model = selection.pieceModelId
|
||||||
? pieceModelMap.get(selection.pieceModelId)
|
? pieceModelMap.get(selection.pieceModelId)
|
||||||
: undefined;
|
: undefined;
|
||||||
const definition = this.normalizePieceSelection(selection, requirement, model);
|
const definition = this.normalizePieceSelection(
|
||||||
|
selection,
|
||||||
|
requirement,
|
||||||
|
model,
|
||||||
|
);
|
||||||
await this.createMachinePiecesFromType(prisma, id, [definition]);
|
await this.createMachinePiecesFromType(prisma, id, [definition]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -842,9 +1050,9 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async resolveConstructeurId(prisma: any, rawName?: string) {
|
private async resolveConstructeurId(prisma: any, rawName?: string) {
|
||||||
if (!rawName) return null
|
if (!rawName) return null;
|
||||||
const name = String(rawName).trim()
|
const name = String(rawName).trim();
|
||||||
if (!name) return null
|
if (!name) return null;
|
||||||
|
|
||||||
const existing = await prisma.constructeur.findFirst({
|
const existing = await prisma.constructeur.findFirst({
|
||||||
where: {
|
where: {
|
||||||
@@ -853,15 +1061,15 @@ export class MachinesService {
|
|||||||
mode: 'insensitive',
|
mode: 'insensitive',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (existing) return existing.id
|
if (existing) return existing.id;
|
||||||
|
|
||||||
const created = await prisma.constructeur.create({
|
const created = await prisma.constructeur.create({
|
||||||
data: { name },
|
data: { name },
|
||||||
})
|
});
|
||||||
|
|
||||||
return created.id
|
return created.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string) {
|
async remove(id: string) {
|
||||||
@@ -983,17 +1191,31 @@ export class MachinesService {
|
|||||||
|
|
||||||
// Traiter les composants existants
|
// Traiter les composants existants
|
||||||
for (const component of machine.composants) {
|
for (const component of machine.composants) {
|
||||||
const typeComponent = components.find((c: any) => c.name === component.name);
|
const typeComponent = components.find(
|
||||||
if (typeComponent && typeComponent.customFields && typeComponent.customFields.length > 0) {
|
(c: any) => c.name === component.name,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
typeComponent &&
|
||||||
|
typeComponent.customFields &&
|
||||||
|
typeComponent.customFields.length > 0
|
||||||
|
) {
|
||||||
// Créer le type de composant s'il n'existe pas
|
// Créer le type de composant s'il n'existe pas
|
||||||
let typeComposant = await this.prisma.typeComposant.findFirst({
|
let typeComposant = await this.prisma.modelType.findFirst({
|
||||||
where: { name: component.name },
|
where: {
|
||||||
|
name: component.name,
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!typeComposant) {
|
if (!typeComposant) {
|
||||||
typeComposant = await this.prisma.typeComposant.create({
|
typeComposant = await this.prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
name: component.name,
|
name: component.name,
|
||||||
|
code: await this.generateUniqueComponentTypeCode(
|
||||||
|
this.prisma,
|
||||||
|
component.name,
|
||||||
|
),
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
description: typeComponent.description || '',
|
description: typeComponent.description || '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1042,7 +1264,10 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!existingValue) {
|
if (!existingValue) {
|
||||||
const defaultValue = typeComponent.customFields.find((cf: any) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
typeComponent.customFields.find(
|
||||||
|
(cf: any) => cf.name === customField.name,
|
||||||
|
)?.defaultValue || '';
|
||||||
await this.prisma.customFieldValue.create({
|
await this.prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
@@ -1055,18 +1280,33 @@ export class MachinesService {
|
|||||||
|
|
||||||
// Traiter les pièces du composant
|
// Traiter les pièces du composant
|
||||||
for (const piece of component.pieces) {
|
for (const piece of component.pieces) {
|
||||||
const typePiece = typeComponent.pieces?.find((p: any) => p.name === piece.name);
|
const typePiece = typeComponent.pieces?.find(
|
||||||
if (typePiece && typePiece.customFields && typePiece.customFields.length > 0) {
|
(p: any) => p.name === piece.name,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
typePiece &&
|
||||||
|
typePiece.customFields &&
|
||||||
|
typePiece.customFields.length > 0
|
||||||
|
) {
|
||||||
// Créer le type de pièce s'il n'existe pas
|
// Créer le type de pièce s'il n'existe pas
|
||||||
let typePieceEntity = await this.prisma.typePiece.findFirst({
|
let typePieceEntity = await this.prisma.modelType.findFirst({
|
||||||
where: { name: piece.name },
|
where: {
|
||||||
|
name: piece.name,
|
||||||
|
category: ModelCategory.PIECE,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!typePieceEntity) {
|
if (!typePieceEntity) {
|
||||||
typePieceEntity = await this.prisma.typePiece.create({
|
typePieceEntity = await this.prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
name: piece.name,
|
name: piece.name,
|
||||||
|
code: await this.generateUniqueComponentTypeCode(
|
||||||
|
this.prisma,
|
||||||
|
piece.name,
|
||||||
|
),
|
||||||
|
category: ModelCategory.PIECE,
|
||||||
description: typePiece.description || '',
|
description: typePiece.description || '',
|
||||||
|
notes: typePiece.description || '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1106,15 +1346,19 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const customField of customFields) {
|
for (const customField of customFields) {
|
||||||
const existingValue = await this.prisma.customFieldValue.findFirst({
|
const existingValue =
|
||||||
where: {
|
await this.prisma.customFieldValue.findFirst({
|
||||||
customFieldId: customField.id,
|
where: {
|
||||||
pieceId: piece.id,
|
customFieldId: customField.id,
|
||||||
},
|
pieceId: piece.id,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!existingValue) {
|
if (!existingValue) {
|
||||||
const defaultValue = typePiece.customFields.find((cf: any) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
typePiece.customFields.find(
|
||||||
|
(cf: any) => cf.name === customField.name,
|
||||||
|
)?.defaultValue || '';
|
||||||
await this.prisma.customFieldValue.create({
|
await this.prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
@@ -1132,17 +1376,30 @@ export class MachinesService {
|
|||||||
// Traiter les pièces de machine
|
// Traiter les pièces de machine
|
||||||
for (const piece of machine.pieces) {
|
for (const piece of machine.pieces) {
|
||||||
const typePiece = machinePieces.find((p: any) => p.name === piece.name);
|
const typePiece = machinePieces.find((p: any) => p.name === piece.name);
|
||||||
if (typePiece && typePiece.customFields && typePiece.customFields.length > 0) {
|
if (
|
||||||
|
typePiece &&
|
||||||
|
typePiece.customFields &&
|
||||||
|
typePiece.customFields.length > 0
|
||||||
|
) {
|
||||||
// Créer le type de pièce s'il n'existe pas
|
// Créer le type de pièce s'il n'existe pas
|
||||||
let typePieceEntity = await this.prisma.typePiece.findFirst({
|
let typePieceEntity = await this.prisma.modelType.findFirst({
|
||||||
where: { name: piece.name },
|
where: {
|
||||||
|
name: piece.name,
|
||||||
|
category: ModelCategory.PIECE,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!typePieceEntity) {
|
if (!typePieceEntity) {
|
||||||
typePieceEntity = await this.prisma.typePiece.create({
|
typePieceEntity = await this.prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
name: piece.name,
|
name: piece.name,
|
||||||
|
code: await this.generateUniqueComponentTypeCode(
|
||||||
|
this.prisma,
|
||||||
|
piece.name,
|
||||||
|
),
|
||||||
|
category: ModelCategory.PIECE,
|
||||||
description: typePiece.description || '',
|
description: typePiece.description || '',
|
||||||
|
notes: typePiece.description || '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1190,7 +1447,10 @@ export class MachinesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!existingValue) {
|
if (!existingValue) {
|
||||||
const defaultValue = typePiece.customFields.find((cf: any) => cf.name === customField.name)?.defaultValue || '';
|
const defaultValue =
|
||||||
|
typePiece.customFields.find(
|
||||||
|
(cf: any) => cf.name === customField.name,
|
||||||
|
)?.defaultValue || '';
|
||||||
await this.prisma.customFieldValue.create({
|
await this.prisma.customFieldValue.create({
|
||||||
data: {
|
data: {
|
||||||
value: defaultValue,
|
value: defaultValue,
|
||||||
|
|||||||
28
src/model-type/dto/create-model-type.dto.ts
Normal file
28
src/model-type/dto/create-model-type.dto.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { IsEnum, IsOptional, IsString, Length, Matches } from 'class-validator';
|
||||||
|
|
||||||
|
export enum ModelCategory {
|
||||||
|
COMPONENT = 'COMPONENT',
|
||||||
|
PIECE = 'PIECE',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateModelTypeDto {
|
||||||
|
@IsString()
|
||||||
|
@Length(2, 120)
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@Length(2, 60)
|
||||||
|
@Matches(/^[a-z0-9\-_.]+$/i)
|
||||||
|
code!: string;
|
||||||
|
|
||||||
|
@IsEnum(ModelCategory)
|
||||||
|
category!: ModelCategory;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
notes?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
5
src/model-type/dto/update-model-type.dto.ts
Normal file
5
src/model-type/dto/update-model-type.dto.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { PartialType } from '@nestjs/mapped-types';
|
||||||
|
import { CreateModelTypeDto } from './create-model-type.dto';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
|
export class UpdateModelTypeDto extends PartialType(CreateModelTypeDto) {}
|
||||||
80
src/model-type/model-type.controller.ts
Normal file
80
src/model-type/model-type.controller.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Header,
|
||||||
|
HttpCode,
|
||||||
|
HttpStatus,
|
||||||
|
Param,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { CreateModelTypeDto, ModelCategory } from './dto/create-model-type.dto';
|
||||||
|
import { UpdateModelTypeDto } from './dto/update-model-type.dto';
|
||||||
|
import { ModelTypeService } from './model-type.service';
|
||||||
|
|
||||||
|
@Controller('api/model-types')
|
||||||
|
export class ModelTypeController {
|
||||||
|
constructor(private readonly modelTypeService: ModelTypeService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
list(
|
||||||
|
@Query('q') q?: string,
|
||||||
|
@Query('category') category?: string,
|
||||||
|
@Query('sort') sort?: 'name' | 'code' | 'createdAt',
|
||||||
|
@Query('dir') dir?: 'asc' | 'desc',
|
||||||
|
@Query('limit') limit?: string,
|
||||||
|
@Query('offset') offset?: string,
|
||||||
|
) {
|
||||||
|
return this.modelTypeService.list({
|
||||||
|
q,
|
||||||
|
category: this.normalizeCategory(category),
|
||||||
|
sort,
|
||||||
|
dir,
|
||||||
|
limit: this.parsePositiveNumber(limit),
|
||||||
|
offset: this.parsePositiveNumber(offset),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@Header('Cache-Control', 'no-store')
|
||||||
|
create(@Body() dto: CreateModelTypeDto) {
|
||||||
|
return this.modelTypeService.create(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
findOne(@Param('id') id: string) {
|
||||||
|
return this.modelTypeService.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
@Header('Cache-Control', 'no-store')
|
||||||
|
update(@Param('id') id: string, @Body() dto: UpdateModelTypeDto) {
|
||||||
|
return this.modelTypeService.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@Header('Cache-Control', 'no-store')
|
||||||
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
|
async remove(@Param('id') id: string) {
|
||||||
|
await this.modelTypeService.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeCategory(value?: string) {
|
||||||
|
if (!value) return undefined;
|
||||||
|
return Object.values(ModelCategory).includes(value as ModelCategory)
|
||||||
|
? (value as ModelCategory)
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parsePositiveNumber(value?: string) {
|
||||||
|
if (value === undefined) return undefined;
|
||||||
|
const parsed = Number.parseInt(value, 10);
|
||||||
|
if (Number.isNaN(parsed) || parsed < 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/model-type/model-type.module.ts
Normal file
9
src/model-type/model-type.module.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ModelTypeController } from './model-type.controller';
|
||||||
|
import { ModelTypeService } from './model-type.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [ModelTypeController],
|
||||||
|
providers: [ModelTypeService],
|
||||||
|
})
|
||||||
|
export class ModelTypeModule {}
|
||||||
159
src/model-type/model-type.service.ts
Normal file
159
src/model-type/model-type.service.ts
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import {
|
||||||
|
ConflictException,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ModelType as PrismaModelType, Prisma } from '@prisma/client';
|
||||||
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { CreateModelTypeDto, ModelCategory } from './dto/create-model-type.dto';
|
||||||
|
import { UpdateModelTypeDto } from './dto/update-model-type.dto';
|
||||||
|
|
||||||
|
type SortField = 'name' | 'code' | 'createdAt';
|
||||||
|
type SortDirection = 'asc' | 'desc';
|
||||||
|
|
||||||
|
interface ListParams {
|
||||||
|
q?: string;
|
||||||
|
category?: ModelCategory;
|
||||||
|
sort?: SortField;
|
||||||
|
dir?: SortDirection;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ModelTypeService {
|
||||||
|
private readonly allowedSortFields: SortField[] = [
|
||||||
|
'name',
|
||||||
|
'code',
|
||||||
|
'createdAt',
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
async list(params: ListParams): Promise<{
|
||||||
|
items: PrismaModelType[];
|
||||||
|
total: number;
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
}> {
|
||||||
|
const {
|
||||||
|
q,
|
||||||
|
category,
|
||||||
|
sort = 'createdAt',
|
||||||
|
dir = 'desc',
|
||||||
|
limit = 20,
|
||||||
|
offset = 0,
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const cappedLimit = Math.min(Math.max(limit ?? 20, 1), 100);
|
||||||
|
const safeOffset = Math.max(offset ?? 0, 0);
|
||||||
|
|
||||||
|
const orderByField = this.allowedSortFields.includes(sort)
|
||||||
|
? sort
|
||||||
|
: 'createdAt';
|
||||||
|
const orderByDir: SortDirection = dir === 'asc' ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
const where: Prisma.ModelTypeWhereInput = {};
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
where.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q?.trim()) {
|
||||||
|
const term = q.trim();
|
||||||
|
where.OR = [
|
||||||
|
{ name: { contains: term, mode: 'insensitive' } },
|
||||||
|
{ code: { contains: term, mode: 'insensitive' } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [items, total] = await this.prisma.$transaction([
|
||||||
|
this.prisma.modelType.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { [orderByField]: orderByDir },
|
||||||
|
skip: safeOffset,
|
||||||
|
take: cappedLimit,
|
||||||
|
}),
|
||||||
|
this.prisma.modelType.count({ where }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
items,
|
||||||
|
total,
|
||||||
|
offset: safeOffset,
|
||||||
|
limit: cappedLimit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(dto: CreateModelTypeDto): Promise<PrismaModelType> {
|
||||||
|
try {
|
||||||
|
return await this.prisma.modelType.create({
|
||||||
|
data: {
|
||||||
|
name: dto.name,
|
||||||
|
code: dto.code,
|
||||||
|
category: dto.category,
|
||||||
|
notes: dto.notes,
|
||||||
|
description: dto.description ?? null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.handlePrismaError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateModelTypeDto): Promise<PrismaModelType> {
|
||||||
|
try {
|
||||||
|
return await this.prisma.modelType.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
...dto,
|
||||||
|
description:
|
||||||
|
dto.description === undefined ? undefined : dto.description ?? null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.handlePrismaError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.prisma.modelType.delete({ where: { id } });
|
||||||
|
} catch (error) {
|
||||||
|
this.handlePrismaError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string): Promise<PrismaModelType> {
|
||||||
|
const modelType = await this.prisma.modelType.findUnique({ where: { id } });
|
||||||
|
if (!modelType) {
|
||||||
|
throw new NotFoundException('Type de modèle introuvable.');
|
||||||
|
}
|
||||||
|
return modelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handlePrismaError(error: unknown): never {
|
||||||
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
|
if (error.code === 'P2002' && this.isUniqueCodeConstraint(error)) {
|
||||||
|
throw new ConflictException('Ce code est déjà utilisé.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.code === 'P2025') {
|
||||||
|
throw new NotFoundException('Type de modèle introuvable.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isUniqueCodeConstraint(error: Prisma.PrismaClientKnownRequestError) {
|
||||||
|
const { target } = error.meta ?? {};
|
||||||
|
if (Array.isArray(target)) {
|
||||||
|
return target.includes('code');
|
||||||
|
}
|
||||||
|
if (typeof target === 'string') {
|
||||||
|
return target === 'code';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,12 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { PiecesService } from './pieces.service';
|
import { PiecesService } from './pieces.service';
|
||||||
import { CreatePieceDto, UpdatePieceDto } from '../shared/dto/piece.dto';
|
import { CreatePieceDto, UpdatePieceDto } from '../shared/dto/piece.dto';
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { PiecesService } from './pieces.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [PiecesController],
|
controllers: [PiecesController],
|
||||||
providers: [PiecesService]
|
providers: [PiecesService],
|
||||||
})
|
})
|
||||||
export class PiecesModule {}
|
export class PiecesModule {}
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ describe('PiecesService', () => {
|
|||||||
prisma.machine.findUnique.mockResolvedValue({
|
prisma.machine.findUnique.mockResolvedValue({
|
||||||
id: 'machine-1',
|
id: 'machine-1',
|
||||||
typeMachine: {
|
typeMachine: {
|
||||||
pieceRequirements: [
|
pieceRequirements: [{ id: 'req-1', typePieceId: 'type-piece-1' }],
|
||||||
{ id: 'req-1', typePieceId: 'type-piece-1' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -70,9 +68,7 @@ describe('PiecesService', () => {
|
|||||||
prisma.machine.findUnique.mockResolvedValue({
|
prisma.machine.findUnique.mockResolvedValue({
|
||||||
id: 'machine-1',
|
id: 'machine-1',
|
||||||
typeMachine: {
|
typeMachine: {
|
||||||
pieceRequirements: [
|
pieceRequirements: [{ id: 'req-1', typePieceId: 'type-piece-1' }],
|
||||||
{ id: 'req-1', typePieceId: 'type-piece-1' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -180,9 +180,7 @@ export class PiecesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!composant) {
|
if (!composant) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException('Le composant spécifié est introuvable.');
|
||||||
'Le composant spécifié est introuvable.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (composant.machineId) {
|
if (composant.machineId) {
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ import { PrismaService } from './prisma.service';
|
|||||||
providers: [PrismaService],
|
providers: [PrismaService],
|
||||||
exports: [PrismaService],
|
exports: [PrismaService],
|
||||||
})
|
})
|
||||||
export class PrismaModule {}
|
export class PrismaModule {}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
export class PrismaService
|
||||||
|
extends PrismaClient
|
||||||
|
implements OnModuleInit, OnModuleDestroy
|
||||||
|
{
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
log: ['query', 'info', 'warn', 'error'],
|
log: ['query', 'info', 'warn', 'error'],
|
||||||
@@ -16,4 +19,4 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModul
|
|||||||
async onModuleDestroy() {
|
async onModuleDestroy() {
|
||||||
await this.$disconnect();
|
await this.$disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'
|
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
|
||||||
import { ProfilesService } from './profiles.service'
|
import { ProfilesService } from './profiles.service';
|
||||||
import { CreateProfileDto } from '../shared/dto/profile.dto'
|
import { CreateProfileDto } from '../shared/dto/profile.dto';
|
||||||
|
|
||||||
@Controller('profiles')
|
@Controller('profiles')
|
||||||
export class ProfilesController {
|
export class ProfilesController {
|
||||||
@@ -8,16 +8,16 @@ export class ProfilesController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
async findAll() {
|
async findAll() {
|
||||||
return this.profilesService.findAllActive()
|
return this.profilesService.findAllActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
async create(@Body() dto: CreateProfileDto) {
|
async create(@Body() dto: CreateProfileDto) {
|
||||||
return this.profilesService.create(dto)
|
return this.profilesService.create(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
async delete(@Param('id') id: string) {
|
async delete(@Param('id') id: string) {
|
||||||
return this.profilesService.deactivate(id)
|
return this.profilesService.deactivate(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common';
|
||||||
import { ProfilesController } from './profiles.controller'
|
import { ProfilesController } from './profiles.controller';
|
||||||
import { ProfilesService } from './profiles.service'
|
import { ProfilesService } from './profiles.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [ProfilesController],
|
controllers: [ProfilesController],
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import { Injectable, NotFoundException, BadRequestException, OnModuleInit } from '@nestjs/common'
|
import {
|
||||||
import { PrismaService } from '../prisma/prisma.service'
|
Injectable,
|
||||||
import { CreateProfileDto } from '../shared/dto/profile.dto'
|
NotFoundException,
|
||||||
|
BadRequestException,
|
||||||
|
OnModuleInit,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { CreateProfileDto } from '../shared/dto/profile.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProfilesService implements OnModuleInit {
|
export class ProfilesService implements OnModuleInit {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
await this.ensureDefaultProfile()
|
await this.ensureDefaultProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllActive() {
|
async findAllActive() {
|
||||||
@@ -21,11 +26,11 @@ export class ProfilesService implements OnModuleInit {
|
|||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findActiveById(profileId: string) {
|
async findActiveById(profileId: string) {
|
||||||
if (!profileId) return null
|
if (!profileId) return null;
|
||||||
|
|
||||||
return this.prisma.profile.findFirst({
|
return this.prisma.profile.findFirst({
|
||||||
where: {
|
where: {
|
||||||
@@ -40,15 +45,15 @@ export class ProfilesService implements OnModuleInit {
|
|||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateProfileDto) {
|
async create(dto: CreateProfileDto) {
|
||||||
const firstName = dto.firstName.trim()
|
const firstName = dto.firstName.trim();
|
||||||
const lastName = dto.lastName.trim()
|
const lastName = dto.lastName.trim();
|
||||||
|
|
||||||
if (!firstName || !lastName) {
|
if (!firstName || !lastName) {
|
||||||
throw new BadRequestException('Le prénom et le nom sont obligatoires.')
|
throw new BadRequestException('Le prénom et le nom sont obligatoires.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.profile.create({
|
return this.prisma.profile.create({
|
||||||
@@ -64,13 +69,15 @@ export class ProfilesService implements OnModuleInit {
|
|||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deactivate(profileId: string) {
|
async deactivate(profileId: string) {
|
||||||
const existing = await this.prisma.profile.findUnique({ where: { id: profileId } })
|
const existing = await this.prisma.profile.findUnique({
|
||||||
|
where: { id: profileId },
|
||||||
|
});
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
throw new NotFoundException('Profil introuvable')
|
throw new NotFoundException('Profil introuvable');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existing.isActive) {
|
if (!existing.isActive) {
|
||||||
@@ -84,7 +91,7 @@ export class ProfilesService implements OnModuleInit {
|
|||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.profile.update({
|
return this.prisma.profile.update({
|
||||||
@@ -98,27 +105,34 @@ export class ProfilesService implements OnModuleInit {
|
|||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ensureDefaultProfile() {
|
private async ensureDefaultProfile() {
|
||||||
const count = await this.prisma.profile.count({ where: { isActive: true } }).catch((err) => {
|
const count = await this.prisma.profile
|
||||||
console.error('Failed to count profiles during ensureDefaultProfile:', err.message)
|
.count({ where: { isActive: true } })
|
||||||
return 0
|
.catch((err) => {
|
||||||
})
|
console.error(
|
||||||
if (count > 0) return
|
'Failed to count profiles during ensureDefaultProfile:',
|
||||||
|
err.message,
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
if (count > 0) return;
|
||||||
|
|
||||||
const firstName = process.env.DEFAULT_PROFILE_FIRST_NAME?.trim() || 'Admin'
|
const firstName = process.env.DEFAULT_PROFILE_FIRST_NAME?.trim() || 'Admin';
|
||||||
const lastName = process.env.DEFAULT_PROFILE_LAST_NAME?.trim() || 'Général'
|
const lastName = process.env.DEFAULT_PROFILE_LAST_NAME?.trim() || 'Général';
|
||||||
|
|
||||||
await this.prisma.profile.create({
|
await this.prisma.profile
|
||||||
data: {
|
.create({
|
||||||
firstName,
|
data: {
|
||||||
lastName,
|
firstName,
|
||||||
isActive: true,
|
lastName,
|
||||||
},
|
isActive: true,
|
||||||
}).catch((err) => {
|
},
|
||||||
console.error('Failed to create default profile:', err.message)
|
})
|
||||||
})
|
.catch((err) => {
|
||||||
|
console.error('Failed to create default profile:', err.message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import {
|
|||||||
Post,
|
Post,
|
||||||
Req,
|
Req,
|
||||||
UnauthorizedException,
|
UnauthorizedException,
|
||||||
} from '@nestjs/common'
|
} from '@nestjs/common';
|
||||||
import { Request } from 'express'
|
import { Request } from 'express';
|
||||||
import { ProfilesService } from '../profiles/profiles.service'
|
import { ProfilesService } from '../profiles/profiles.service';
|
||||||
import { ActivateProfileDto } from '../shared/dto/profile.dto'
|
import { ActivateProfileDto } from '../shared/dto/profile.dto';
|
||||||
|
|
||||||
@Controller('session/profile')
|
@Controller('session/profile')
|
||||||
export class ProfileSessionController {
|
export class ProfileSessionController {
|
||||||
@@ -19,46 +19,50 @@ export class ProfileSessionController {
|
|||||||
@Get()
|
@Get()
|
||||||
async getActiveProfile(@Req() req: Request) {
|
async getActiveProfile(@Req() req: Request) {
|
||||||
if (!req.session?.profileId) {
|
if (!req.session?.profileId) {
|
||||||
throw new UnauthorizedException('Aucun profil actif.')
|
throw new UnauthorizedException('Aucun profil actif.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const profile = await this.profilesService.findActiveById(req.session.profileId)
|
const profile = await this.profilesService.findActiveById(
|
||||||
|
req.session.profileId,
|
||||||
|
);
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
req.session.profileId = undefined
|
req.session.profileId = undefined;
|
||||||
throw new UnauthorizedException('Profil introuvable ou inactif.')
|
throw new UnauthorizedException('Profil introuvable ou inactif.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return profile
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
async activateProfile(@Req() req: Request, @Body() dto: ActivateProfileDto) {
|
async activateProfile(@Req() req: Request, @Body() dto: ActivateProfileDto) {
|
||||||
if (!dto.profileId) {
|
if (!dto.profileId) {
|
||||||
throw new BadRequestException('profileId est requis.')
|
throw new BadRequestException('profileId est requis.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const profile = await this.profilesService.findActiveById(dto.profileId)
|
const profile = await this.profilesService.findActiveById(dto.profileId);
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
throw new UnauthorizedException('Profil introuvable ou inactif.')
|
throw new UnauthorizedException('Profil introuvable ou inactif.');
|
||||||
}
|
}
|
||||||
|
|
||||||
req.session.profileId = profile.id
|
req.session.profileId = profile.id;
|
||||||
return profile
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete()
|
@Delete()
|
||||||
async logout(@Req() req: Request) {
|
async logout(@Req() req: Request) {
|
||||||
if (!req.session) {
|
if (!req.session) {
|
||||||
return { success: true }
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
req.session.destroy((err) => {
|
req.session.destroy((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return reject(new BadRequestException('Impossible de déconnecter la session.'))
|
return reject(
|
||||||
|
new BadRequestException('Impossible de déconnecter la session.'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
resolve({ success: true })
|
resolve({ success: true });
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common';
|
||||||
import { ProfileSessionController } from './session.controller'
|
import { ProfileSessionController } from './session.controller';
|
||||||
import { ProfilesModule } from '../profiles/profiles.module'
|
import { ProfilesModule } from '../profiles/profiles.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ProfilesModule],
|
imports: [ProfilesModule],
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class CreateComposantDto {
|
|||||||
constructeurId?: string;
|
constructeurId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => value === '' ? null : value)
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@IsNumber({}, { message: 'prix must be a valid number' })
|
@IsNumber({}, { message: 'prix must be a valid number' })
|
||||||
prix?: number | null;
|
prix?: number | null;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ export class UpdateComposantDto {
|
|||||||
constructeurId?: string;
|
constructeurId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => value === '' ? null : value)
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@IsNumber({}, { message: 'prix must be a valid number' })
|
@IsNumber({}, { message: 'prix must be a valid number' })
|
||||||
prix?: number | null;
|
prix?: number | null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import { IsEmail, IsOptional, IsString } from 'class-validator'
|
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateConstructeurDto {
|
export class CreateConstructeurDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
name: string
|
name: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
email?: string
|
email?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
phone?: string
|
phone?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateConstructeurDto {
|
export class UpdateConstructeurDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
name?: string
|
name?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
email?: string
|
email?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
phone?: string
|
phone?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,4 +58,4 @@ export class UpdateCustomFieldValueDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,8 @@ export class MachinePieceSelectionDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
requirementId: string;
|
requirementId: string;
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
@IsString()
|
||||||
pieceModelId?: string;
|
pieceModelId: string;
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
definition?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateMachineDto {
|
export class CreateMachineDto {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class CreatePieceDto {
|
|||||||
constructeurId?: string;
|
constructeurId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => value === '' ? null : value)
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@IsNumber({}, { message: 'prix must be a valid number' })
|
@IsNumber({}, { message: 'prix must be a valid number' })
|
||||||
prix?: number | null;
|
prix?: number | null;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ export class UpdatePieceDto {
|
|||||||
constructeurId?: string;
|
constructeurId?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => value === '' ? null : value)
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@IsNumber({}, { message: 'prix must be a valid number' })
|
@IsNumber({}, { message: 'prix must be a valid number' })
|
||||||
prix?: number | null;
|
prix?: number | null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { IsNotEmpty, IsString, MaxLength } from 'class-validator'
|
import { IsNotEmpty, IsString, MaxLength } from 'class-validator';
|
||||||
|
|
||||||
export class CreateProfileDto {
|
export class CreateProfileDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@MaxLength(100)
|
@MaxLength(100)
|
||||||
firstName!: string
|
firstName!: string;
|
||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@MaxLength(100)
|
@MaxLength(100)
|
||||||
lastName!: string
|
lastName!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActivateProfileDto {
|
export class ActivateProfileDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
profileId!: string
|
profileId!: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { IsString, IsOptional, IsArray, IsObject, IsBoolean, IsEnum, IsInt } from 'class-validator';
|
import {
|
||||||
|
IsString,
|
||||||
|
IsOptional,
|
||||||
|
IsArray,
|
||||||
|
IsObject,
|
||||||
|
IsBoolean,
|
||||||
|
IsEnum,
|
||||||
|
IsInt,
|
||||||
|
} from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { ValidateNested } from 'class-validator';
|
import { ValidateNested } from 'class-validator';
|
||||||
|
|
||||||
@@ -7,7 +15,7 @@ export enum CustomFieldType {
|
|||||||
NUMBER = 'number',
|
NUMBER = 'number',
|
||||||
SELECT = 'select',
|
SELECT = 'select',
|
||||||
BOOLEAN = 'boolean',
|
BOOLEAN = 'boolean',
|
||||||
DATE = 'date'
|
DATE = 'date',
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateCustomFieldDto {
|
export class CreateCustomFieldDto {
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { SitesService } from './sites.service';
|
import { SitesService } from './sites.service';
|
||||||
import { CreateSiteDto, UpdateSiteDto } from '../shared/dto/site.dto';
|
import { CreateSiteDto, UpdateSiteDto } from '../shared/dto/site.dto';
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { SitesService } from './sites.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [SitesController],
|
controllers: [SitesController],
|
||||||
providers: [SitesService]
|
providers: [SitesService],
|
||||||
})
|
})
|
||||||
export class SitesModule {}
|
export class SitesModule {}
|
||||||
|
|||||||
@@ -70,10 +70,10 @@ export class SitesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (machinesInSite.length > 0) {
|
if (machinesInSite.length > 0) {
|
||||||
const machineNames = machinesInSite.map(m => m.name).join(', ');
|
const machineNames = machinesInSite.map((m) => m.name).join(', ');
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Impossible de supprimer ce site car il contient ${machinesInSite.length} machine(s): ${machineNames}. ` +
|
`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.`
|
`Veuillez d'abord supprimer ou déplacer ces machines vers un autre site.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
src/types/express-session.d.ts
vendored
4
src/types/express-session.d.ts
vendored
@@ -1,7 +1,7 @@
|
|||||||
import 'express-session'
|
import 'express-session';
|
||||||
|
|
||||||
declare module 'express-session' {
|
declare module 'express-session' {
|
||||||
interface SessionData {
|
interface SessionData {
|
||||||
profileId?: string
|
profileId?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Patch,
|
||||||
|
Param,
|
||||||
|
Delete,
|
||||||
|
Query,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { TypesService } from './types.service';
|
import { TypesService } from './types.service';
|
||||||
import {
|
import {
|
||||||
CreateTypeMachineDto,
|
CreateTypeMachineDto,
|
||||||
UpdateTypeMachineDto,
|
UpdateTypeMachineDto,
|
||||||
CreateTypeComposantDto,
|
CreateTypeComposantDto,
|
||||||
UpdateTypeComposantDto,
|
UpdateTypeComposantDto,
|
||||||
@@ -10,7 +19,7 @@ import {
|
|||||||
CreateComposantModelDto,
|
CreateComposantModelDto,
|
||||||
UpdateComposantModelDto,
|
UpdateComposantModelDto,
|
||||||
CreatePieceModelDto,
|
CreatePieceModelDto,
|
||||||
UpdatePieceModelDto
|
UpdatePieceModelDto,
|
||||||
} from '../shared/dto/type.dto';
|
} from '../shared/dto/type.dto';
|
||||||
|
|
||||||
@Controller('types')
|
@Controller('types')
|
||||||
@@ -34,7 +43,10 @@ export class TypesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch('machines/:id')
|
@Patch('machines/:id')
|
||||||
updateTypeMachine(@Param('id') id: string, @Body() updateTypeMachineDto: UpdateTypeMachineDto) {
|
updateTypeMachine(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateTypeMachineDto: UpdateTypeMachineDto,
|
||||||
|
) {
|
||||||
return this.typesService.updateTypeMachine(id, updateTypeMachineDto);
|
return this.typesService.updateTypeMachine(id, updateTypeMachineDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +68,9 @@ export class TypesController {
|
|||||||
|
|
||||||
// ComposantModel routes
|
// ComposantModel routes
|
||||||
@Post('composants/models')
|
@Post('composants/models')
|
||||||
createComposantModel(@Body() createComposantModelDto: CreateComposantModelDto) {
|
createComposantModel(
|
||||||
|
@Body() createComposantModelDto: CreateComposantModelDto,
|
||||||
|
) {
|
||||||
return this.typesService.createComposantModel(createComposantModelDto);
|
return this.typesService.createComposantModel(createComposantModelDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +85,10 @@ export class TypesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch('composants/models/:id')
|
@Patch('composants/models/:id')
|
||||||
updateComposantModel(@Param('id') id: string, @Body() updateComposantModelDto: UpdateComposantModelDto) {
|
updateComposantModel(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateComposantModelDto: UpdateComposantModelDto,
|
||||||
|
) {
|
||||||
return this.typesService.updateComposantModel(id, updateComposantModelDto);
|
return this.typesService.updateComposantModel(id, updateComposantModelDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +103,10 @@ export class TypesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch('composants/:id')
|
@Patch('composants/:id')
|
||||||
updateTypeComposant(@Param('id') id: string, @Body() updateTypeComposantDto: UpdateTypeComposantDto) {
|
updateTypeComposant(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateTypeComposantDto: UpdateTypeComposantDto,
|
||||||
|
) {
|
||||||
return this.typesService.updateTypeComposant(id, updateTypeComposantDto);
|
return this.typesService.updateTypeComposant(id, updateTypeComposantDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +143,10 @@ export class TypesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch('pieces/models/:id')
|
@Patch('pieces/models/:id')
|
||||||
updatePieceModel(@Param('id') id: string, @Body() updatePieceModelDto: UpdatePieceModelDto) {
|
updatePieceModel(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updatePieceModelDto: UpdatePieceModelDto,
|
||||||
|
) {
|
||||||
return this.typesService.updatePieceModel(id, updatePieceModelDto);
|
return this.typesService.updatePieceModel(id, updatePieceModelDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +161,10 @@ export class TypesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch('pieces/:id')
|
@Patch('pieces/:id')
|
||||||
updateTypePiece(@Param('id') id: string, @Body() updateTypePieceDto: UpdateTypePieceDto) {
|
updateTypePiece(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() updateTypePieceDto: UpdateTypePieceDto,
|
||||||
|
) {
|
||||||
return this.typesService.updateTypePiece(id, updateTypePieceDto);
|
return this.typesService.updateTypePiece(id, updateTypePieceDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { TypesService } from './types.service';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [TypesController],
|
controllers: [TypesController],
|
||||||
providers: [TypesService]
|
providers: [TypesService],
|
||||||
})
|
})
|
||||||
export class TypesModule {}
|
export class TypesModule {}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ModelCategory } from '@prisma/client';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import {
|
import {
|
||||||
CreateTypeMachineDto,
|
CreateTypeMachineDto,
|
||||||
UpdateTypeMachineDto,
|
UpdateTypeMachineDto,
|
||||||
CreateTypeComposantDto,
|
CreateTypeComposantDto,
|
||||||
UpdateTypeComposantDto,
|
UpdateTypeComposantDto,
|
||||||
@@ -10,53 +11,93 @@ import {
|
|||||||
CreateComposantModelDto,
|
CreateComposantModelDto,
|
||||||
UpdateComposantModelDto,
|
UpdateComposantModelDto,
|
||||||
CreatePieceModelDto,
|
CreatePieceModelDto,
|
||||||
UpdatePieceModelDto
|
UpdatePieceModelDto,
|
||||||
} from '../shared/dto/type.dto';
|
} from '../shared/dto/type.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TypesService {
|
export class TypesService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private slugifyName(name: string): string {
|
||||||
|
return name
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
.replace(/-+/g, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateUniqueModelTypeCode(name: string): Promise<string> {
|
||||||
|
const base = this.slugifyName(name) || 'type';
|
||||||
|
let candidate = base;
|
||||||
|
let suffix = 1;
|
||||||
|
|
||||||
|
while (
|
||||||
|
await this.prisma.modelType.findUnique({
|
||||||
|
where: { code: candidate },
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
candidate = `${base}-${suffix++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
// TypeMachine methods
|
// TypeMachine methods
|
||||||
async createTypeMachine(createTypeMachineDto: CreateTypeMachineDto) {
|
async createTypeMachine(createTypeMachineDto: CreateTypeMachineDto) {
|
||||||
const { customFields, componentRequirements, pieceRequirements, ...typeData } = createTypeMachineDto;
|
const {
|
||||||
|
customFields,
|
||||||
|
componentRequirements,
|
||||||
|
pieceRequirements,
|
||||||
|
...typeData
|
||||||
|
} = createTypeMachineDto;
|
||||||
|
|
||||||
return this.prisma.typeMachine.create({
|
return this.prisma.typeMachine.create({
|
||||||
data: {
|
data: {
|
||||||
...typeData,
|
...typeData,
|
||||||
customFields: customFields ? {
|
customFields: customFields
|
||||||
create: customFields.map(field => ({
|
? {
|
||||||
name: field.name,
|
create: customFields.map((field) => ({
|
||||||
type: field.type,
|
name: field.name,
|
||||||
required: field.required || false,
|
type: field.type,
|
||||||
defaultValue: field.defaultValue,
|
required: field.required || false,
|
||||||
options: field.options
|
defaultValue: field.defaultValue,
|
||||||
}))
|
options: field.options,
|
||||||
} : undefined,
|
})),
|
||||||
componentRequirements: componentRequirements && componentRequirements.length > 0 ? {
|
}
|
||||||
create: componentRequirements.map(requirement => ({
|
: undefined,
|
||||||
label: requirement.label,
|
componentRequirements:
|
||||||
minCount: requirement.minCount ?? 1,
|
componentRequirements && componentRequirements.length > 0
|
||||||
maxCount: requirement.maxCount ?? null,
|
? {
|
||||||
required: requirement.required ?? true,
|
create: componentRequirements.map((requirement) => ({
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
label: requirement.label,
|
||||||
typeComposant: {
|
minCount: requirement.minCount ?? 1,
|
||||||
connect: { id: requirement.typeComposantId },
|
maxCount: requirement.maxCount ?? null,
|
||||||
},
|
required: requirement.required ?? true,
|
||||||
}))
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
} : undefined,
|
typeComposant: {
|
||||||
pieceRequirements: pieceRequirements && pieceRequirements.length > 0 ? {
|
connect: { id: requirement.typeComposantId },
|
||||||
create: pieceRequirements.map(requirement => ({
|
},
|
||||||
label: requirement.label,
|
})),
|
||||||
minCount: requirement.minCount ?? 0,
|
}
|
||||||
maxCount: requirement.maxCount ?? null,
|
: undefined,
|
||||||
required: requirement.required ?? false,
|
pieceRequirements:
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
pieceRequirements && pieceRequirements.length > 0
|
||||||
typePiece: {
|
? {
|
||||||
connect: { id: requirement.typePieceId },
|
create: pieceRequirements.map((requirement) => ({
|
||||||
},
|
label: requirement.label,
|
||||||
}))
|
minCount: requirement.minCount ?? 0,
|
||||||
} : undefined,
|
maxCount: requirement.maxCount ?? null,
|
||||||
|
required: requirement.required ?? false,
|
||||||
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
|
typePiece: {
|
||||||
|
connect: { id: requirement.typePieceId },
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -113,27 +154,35 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypeMachine(id: string, updateTypeMachineDto: UpdateTypeMachineDto) {
|
async updateTypeMachine(
|
||||||
const { customFields, componentRequirements, pieceRequirements, ...typeData } = updateTypeMachineDto;
|
id: string,
|
||||||
|
updateTypeMachineDto: UpdateTypeMachineDto,
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
customFields,
|
||||||
|
componentRequirements,
|
||||||
|
pieceRequirements,
|
||||||
|
...typeData
|
||||||
|
} = updateTypeMachineDto;
|
||||||
|
|
||||||
// Si des champs personnalisés sont fournis, on les met à jour
|
// Si des champs personnalisés sont fournis, on les met à jour
|
||||||
if (customFields !== undefined) {
|
if (customFields !== undefined) {
|
||||||
// Supprimer tous les champs personnalisés existants
|
// Supprimer tous les champs personnalisés existants
|
||||||
await this.prisma.customField.deleteMany({
|
await this.prisma.customField.deleteMany({
|
||||||
where: { typeMachineId: id }
|
where: { typeMachineId: id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Créer les nouveaux champs personnalisés
|
// Créer les nouveaux champs personnalisés
|
||||||
if (customFields.length > 0) {
|
if (customFields.length > 0) {
|
||||||
await this.prisma.customField.createMany({
|
await this.prisma.customField.createMany({
|
||||||
data: customFields.map(field => ({
|
data: customFields.map((field) => ({
|
||||||
name: field.name,
|
name: field.name,
|
||||||
type: field.type,
|
type: field.type,
|
||||||
required: field.required || false,
|
required: field.required || false,
|
||||||
defaultValue: field.defaultValue,
|
defaultValue: field.defaultValue,
|
||||||
options: field.options,
|
options: field.options,
|
||||||
typeMachineId: id
|
typeMachineId: id,
|
||||||
}))
|
})),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +194,7 @@ export class TypesService {
|
|||||||
|
|
||||||
if (componentRequirements.length > 0) {
|
if (componentRequirements.length > 0) {
|
||||||
await this.prisma.typeMachineComponentRequirement.createMany({
|
await this.prisma.typeMachineComponentRequirement.createMany({
|
||||||
data: componentRequirements.map(requirement => ({
|
data: componentRequirements.map((requirement) => ({
|
||||||
label: requirement.label ?? null,
|
label: requirement.label ?? null,
|
||||||
minCount: requirement.minCount ?? 1,
|
minCount: requirement.minCount ?? 1,
|
||||||
maxCount: requirement.maxCount ?? null,
|
maxCount: requirement.maxCount ?? null,
|
||||||
@@ -166,7 +215,7 @@ export class TypesService {
|
|||||||
|
|
||||||
if (pieceRequirements.length > 0) {
|
if (pieceRequirements.length > 0) {
|
||||||
await this.prisma.typeMachinePieceRequirement.createMany({
|
await this.prisma.typeMachinePieceRequirement.createMany({
|
||||||
data: pieceRequirements.map(requirement => ({
|
data: pieceRequirements.map((requirement) => ({
|
||||||
label: requirement.label ?? null,
|
label: requirement.label ?? null,
|
||||||
minCount: requirement.minCount ?? 0,
|
minCount: requirement.minCount ?? 0,
|
||||||
maxCount: requirement.maxCount ?? null,
|
maxCount: requirement.maxCount ?? null,
|
||||||
@@ -179,7 +228,7 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.typeMachine.update({
|
return this.prisma.typeMachine.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: typeData,
|
data: typeData,
|
||||||
@@ -207,10 +256,10 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (machinesWithType.length > 0) {
|
if (machinesWithType.length > 0) {
|
||||||
const machineNames = machinesWithType.map(m => m.name).join(', ');
|
const machineNames = machinesWithType.map((m) => m.name).join(', ');
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Impossible de supprimer ce type de machine car il est utilisé par ${machinesWithType.length} machine(s): ${machineNames}. ` +
|
`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.`
|
`Veuillez d'abord supprimer ou modifier ces machines.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,22 +273,30 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeComposant methods
|
// TypeComposant methods (backed by ModelType with COMPONENT category)
|
||||||
async createTypeComposant(createTypeComposantDto: CreateTypeComposantDto) {
|
async createTypeComposant(createTypeComposantDto: CreateTypeComposantDto) {
|
||||||
const { customFields, ...typeData } = createTypeComposantDto;
|
const { customFields, description, name } = createTypeComposantDto;
|
||||||
|
|
||||||
return this.prisma.typeComposant.create({
|
const code = await this.generateUniqueModelTypeCode(name);
|
||||||
|
|
||||||
|
return this.prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
...typeData,
|
name,
|
||||||
customFields: customFields ? {
|
code,
|
||||||
create: customFields.map(field => ({
|
category: ModelCategory.COMPONENT,
|
||||||
name: field.name,
|
description: description ?? null,
|
||||||
type: field.type,
|
notes: description ?? null,
|
||||||
required: field.required || false,
|
customFields: customFields
|
||||||
defaultValue: field.defaultValue,
|
? {
|
||||||
options: field.options
|
create: customFields.map((field) => ({
|
||||||
}))
|
name: field.name,
|
||||||
} : undefined
|
type: field.type,
|
||||||
|
required: field.required || false,
|
||||||
|
defaultValue: field.defaultValue,
|
||||||
|
options: field.options,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -248,7 +305,8 @@ export class TypesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findAllTypeComposants() {
|
async findAllTypeComposants() {
|
||||||
return this.prisma.typeComposant.findMany({
|
return this.prisma.modelType.findMany({
|
||||||
|
where: { category: ModelCategory.COMPONENT },
|
||||||
include: {
|
include: {
|
||||||
composants: true,
|
composants: true,
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -258,8 +316,11 @@ export class TypesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findOneTypeComposant(id: string) {
|
async findOneTypeComposant(id: string) {
|
||||||
return this.prisma.typeComposant.findUnique({
|
return this.prisma.modelType.findFirst({
|
||||||
where: { id },
|
where: {
|
||||||
|
id,
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
|
},
|
||||||
include: {
|
include: {
|
||||||
composants: true,
|
composants: true,
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -268,34 +329,43 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypeComposant(id: string, updateTypeComposantDto: UpdateTypeComposantDto) {
|
async updateTypeComposant(
|
||||||
const { customFields, ...typeData } = updateTypeComposantDto;
|
id: string,
|
||||||
|
updateTypeComposantDto: UpdateTypeComposantDto,
|
||||||
// Si des champs personnalisés sont fournis, on les met à jour
|
) {
|
||||||
|
const { customFields, description, name } = updateTypeComposantDto;
|
||||||
|
|
||||||
if (customFields !== undefined) {
|
if (customFields !== undefined) {
|
||||||
// Supprimer tous les champs personnalisés existants
|
|
||||||
await this.prisma.customField.deleteMany({
|
await this.prisma.customField.deleteMany({
|
||||||
where: { typeComposantId: id }
|
where: { typeComposantId: id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Créer les nouveaux champs personnalisés
|
|
||||||
if (customFields.length > 0) {
|
if (customFields.length > 0) {
|
||||||
await this.prisma.customField.createMany({
|
await this.prisma.customField.createMany({
|
||||||
data: customFields.map(field => ({
|
data: customFields.map((field) => ({
|
||||||
name: field.name,
|
name: field.name,
|
||||||
type: field.type,
|
type: field.type,
|
||||||
required: field.required || false,
|
required: field.required || false,
|
||||||
defaultValue: field.defaultValue,
|
defaultValue: field.defaultValue,
|
||||||
options: field.options,
|
options: field.options,
|
||||||
typeComposantId: id
|
typeComposantId: id,
|
||||||
}))
|
})),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.typeComposant.update({
|
const data: Record<string, unknown> = {};
|
||||||
|
if (name !== undefined) {
|
||||||
|
data.name = name;
|
||||||
|
}
|
||||||
|
if (description !== undefined) {
|
||||||
|
data.description = description;
|
||||||
|
data.notes = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prisma.modelType.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: typeData,
|
data,
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
customFields: true,
|
||||||
},
|
},
|
||||||
@@ -303,91 +373,145 @@ export class TypesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async removeTypeComposant(id: string) {
|
async removeTypeComposant(id: string) {
|
||||||
return this.prisma.typeComposant.delete({
|
return this.prisma.modelType.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypePiece methods
|
// TypePiece methods backed by ModelType
|
||||||
|
private mapModelTypePiece(modelType: any) {
|
||||||
|
if (!modelType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
pieceCustomFields,
|
||||||
|
pieceModels,
|
||||||
|
pieceRequirements,
|
||||||
|
pieces,
|
||||||
|
...rest
|
||||||
|
} = modelType;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
customFields: pieceCustomFields ?? [],
|
||||||
|
models: pieceModels ?? [],
|
||||||
|
pieceRequirements: pieceRequirements ?? [],
|
||||||
|
pieces: pieces ?? [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async createTypePiece(createTypePieceDto: CreateTypePieceDto) {
|
async createTypePiece(createTypePieceDto: CreateTypePieceDto) {
|
||||||
const { customFields, ...typeData } = createTypePieceDto;
|
const { customFields, description, name } = createTypePieceDto;
|
||||||
|
|
||||||
return this.prisma.typePiece.create({
|
const code = await this.generateUniqueModelTypeCode(name);
|
||||||
|
|
||||||
|
const created = await this.prisma.modelType.create({
|
||||||
data: {
|
data: {
|
||||||
...typeData,
|
name,
|
||||||
customFields: customFields ? {
|
code,
|
||||||
create: customFields.map(field => ({
|
category: ModelCategory.PIECE,
|
||||||
name: field.name,
|
description: description ?? null,
|
||||||
type: field.type,
|
notes: description ?? null,
|
||||||
required: field.required || false,
|
pieceCustomFields: customFields
|
||||||
defaultValue: field.defaultValue,
|
? {
|
||||||
options: field.options
|
create: customFields.map((field) => ({
|
||||||
}))
|
name: field.name,
|
||||||
} : undefined
|
type: field.type,
|
||||||
|
required: field.required || false,
|
||||||
|
defaultValue: field.defaultValue,
|
||||||
|
options: field.options,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
pieceCustomFields: true,
|
||||||
|
pieceModels: true,
|
||||||
|
pieceRequirements: true,
|
||||||
|
pieces: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.mapModelTypePiece(created);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllTypePieces() {
|
async findAllTypePieces() {
|
||||||
return this.prisma.typePiece.findMany({
|
const items = await this.prisma.modelType.findMany({
|
||||||
|
where: { category: ModelCategory.PIECE },
|
||||||
include: {
|
include: {
|
||||||
|
pieceCustomFields: true,
|
||||||
|
pieceModels: true,
|
||||||
|
pieceRequirements: true,
|
||||||
pieces: true,
|
pieces: true,
|
||||||
customFields: true,
|
|
||||||
models: true,
|
|
||||||
},
|
},
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return items.map((item) => this.mapModelTypePiece(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneTypePiece(id: string) {
|
async findOneTypePiece(id: string) {
|
||||||
return this.prisma.typePiece.findUnique({
|
const item = await this.prisma.modelType.findFirst({
|
||||||
where: { id },
|
where: { id, category: ModelCategory.PIECE },
|
||||||
include: {
|
include: {
|
||||||
|
pieceCustomFields: true,
|
||||||
|
pieceModels: true,
|
||||||
|
pieceRequirements: true,
|
||||||
pieces: true,
|
pieces: true,
|
||||||
customFields: true,
|
|
||||||
models: true,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.mapModelTypePiece(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypePiece(id: string, updateTypePieceDto: UpdateTypePieceDto) {
|
async updateTypePiece(id: string, updateTypePieceDto: UpdateTypePieceDto) {
|
||||||
const { customFields, ...typeData } = updateTypePieceDto;
|
const { customFields, description, name } = updateTypePieceDto;
|
||||||
|
|
||||||
// Si des champs personnalisés sont fournis, on les met à jour
|
|
||||||
if (customFields !== undefined) {
|
if (customFields !== undefined) {
|
||||||
// Supprimer tous les champs personnalisés existants
|
|
||||||
await this.prisma.customField.deleteMany({
|
await this.prisma.customField.deleteMany({
|
||||||
where: { typePieceId: id }
|
where: { typePieceId: id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Créer les nouveaux champs personnalisés
|
|
||||||
if (customFields.length > 0) {
|
if (customFields.length > 0) {
|
||||||
await this.prisma.customField.createMany({
|
await this.prisma.customField.createMany({
|
||||||
data: customFields.map(field => ({
|
data: customFields.map((field) => ({
|
||||||
name: field.name,
|
name: field.name,
|
||||||
type: field.type,
|
type: field.type,
|
||||||
required: field.required || false,
|
required: field.required || false,
|
||||||
defaultValue: field.defaultValue,
|
defaultValue: field.defaultValue,
|
||||||
options: field.options,
|
options: field.options,
|
||||||
typePieceId: id
|
typePieceId: id,
|
||||||
}))
|
})),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.typePiece.update({
|
const updatePayload: Record<string, unknown> = {};
|
||||||
|
if (name !== undefined) {
|
||||||
|
updatePayload.name = name;
|
||||||
|
}
|
||||||
|
if (description !== undefined) {
|
||||||
|
updatePayload.description = description;
|
||||||
|
updatePayload.notes = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = await this.prisma.modelType.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: typeData,
|
data: updatePayload,
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
pieceCustomFields: true,
|
||||||
|
pieceModels: true,
|
||||||
|
pieceRequirements: true,
|
||||||
|
pieces: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.mapModelTypePiece(updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeTypePiece(id: string) {
|
async removeTypePiece(id: string) {
|
||||||
return this.prisma.typePiece.delete({
|
return this.prisma.modelType.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -430,7 +554,10 @@ export class TypesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateComposantModel(id: string, updateComposantModelDto: UpdateComposantModelDto) {
|
async updateComposantModel(
|
||||||
|
id: string,
|
||||||
|
updateComposantModelDto: UpdateComposantModelDto,
|
||||||
|
) {
|
||||||
const { typeComposantId, ...data } = updateComposantModelDto;
|
const { typeComposantId, ...data } = updateComposantModelDto;
|
||||||
|
|
||||||
return this.prisma.composantModel.update({
|
return this.prisma.composantModel.update({
|
||||||
|
|||||||
@@ -156,9 +156,12 @@ class InMemoryPrismaService {
|
|||||||
private sites: SiteRecord[] = [];
|
private sites: SiteRecord[] = [];
|
||||||
private typeComposants: TypeComposantRecord[] = [];
|
private typeComposants: TypeComposantRecord[] = [];
|
||||||
private typePieces: TypePieceRecord[] = [];
|
private typePieces: TypePieceRecord[] = [];
|
||||||
|
private modelTypeCodeCounter = 0;
|
||||||
private typeMachines: TypeMachineRecord[] = [];
|
private typeMachines: TypeMachineRecord[] = [];
|
||||||
private typeMachineComponentRequirements: TypeMachineComponentRequirementRecord[] = [];
|
private typeMachineComponentRequirements: TypeMachineComponentRequirementRecord[] =
|
||||||
private typeMachinePieceRequirements: TypeMachinePieceRequirementRecord[] = [];
|
[];
|
||||||
|
private typeMachinePieceRequirements: TypeMachinePieceRequirementRecord[] =
|
||||||
|
[];
|
||||||
private machines: MachineRecord[] = [];
|
private machines: MachineRecord[] = [];
|
||||||
private composants: ComposantRecord[] = [];
|
private composants: ComposantRecord[] = [];
|
||||||
private pieces: PieceRecord[] = [];
|
private pieces: PieceRecord[] = [];
|
||||||
@@ -179,6 +182,7 @@ class InMemoryPrismaService {
|
|||||||
this.sites = [];
|
this.sites = [];
|
||||||
this.typeComposants = [];
|
this.typeComposants = [];
|
||||||
this.typePieces = [];
|
this.typePieces = [];
|
||||||
|
this.modelTypeCodeCounter = 0;
|
||||||
this.typeMachines = [];
|
this.typeMachines = [];
|
||||||
this.typeMachineComponentRequirements = [];
|
this.typeMachineComponentRequirements = [];
|
||||||
this.typeMachinePieceRequirements = [];
|
this.typeMachinePieceRequirements = [];
|
||||||
@@ -268,7 +272,9 @@ class InMemoryPrismaService {
|
|||||||
return include?.customFields
|
return include?.customFields
|
||||||
? {
|
? {
|
||||||
...record,
|
...record,
|
||||||
customFields: this.customFields.filter((field) => field.typeComposantId === record.id),
|
customFields: this.customFields.filter(
|
||||||
|
(field) => field.typeComposantId === record.id,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
: { ...record };
|
: { ...record };
|
||||||
},
|
},
|
||||||
@@ -280,7 +286,9 @@ class InMemoryPrismaService {
|
|||||||
return this.typeComposants.find((item) => item.id === where.id) ?? null;
|
return this.typeComposants.find((item) => item.id === where.id) ?? null;
|
||||||
}
|
}
|
||||||
if (where.name) {
|
if (where.name) {
|
||||||
return this.typeComposants.find((item) => item.name === where.name) ?? null;
|
return (
|
||||||
|
this.typeComposants.find((item) => item.name === where.name) ?? null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@@ -325,7 +333,9 @@ class InMemoryPrismaService {
|
|||||||
return include?.customFields
|
return include?.customFields
|
||||||
? {
|
? {
|
||||||
...record,
|
...record,
|
||||||
customFields: this.customFields.filter((field) => field.typePieceId === record.id),
|
customFields: this.customFields.filter(
|
||||||
|
(field) => field.typePieceId === record.id,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
: { ...record };
|
: { ...record };
|
||||||
},
|
},
|
||||||
@@ -383,20 +393,22 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
let componentRequirements: TypeMachineComponentRequirementRecord[] = [];
|
let componentRequirements: TypeMachineComponentRequirementRecord[] = [];
|
||||||
if (data.componentRequirements?.create) {
|
if (data.componentRequirements?.create) {
|
||||||
componentRequirements = data.componentRequirements.create.map((requirement) => {
|
componentRequirements = data.componentRequirements.create.map(
|
||||||
const req: TypeMachineComponentRequirementRecord = {
|
(requirement) => {
|
||||||
id: generateId('tmc_req'),
|
const req: TypeMachineComponentRequirementRecord = {
|
||||||
typeMachineId: record.id,
|
id: generateId('tmc_req'),
|
||||||
typeComposantId: requirement.typeComposant.connect.id,
|
typeMachineId: record.id,
|
||||||
label: requirement.label ?? null,
|
typeComposantId: requirement.typeComposant.connect.id,
|
||||||
minCount: requirement.minCount ?? 1,
|
label: requirement.label ?? null,
|
||||||
maxCount: requirement.maxCount ?? null,
|
minCount: requirement.minCount ?? 1,
|
||||||
required: requirement.required ?? true,
|
maxCount: requirement.maxCount ?? null,
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
required: requirement.required ?? true,
|
||||||
};
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
this.typeMachineComponentRequirements.push(req);
|
};
|
||||||
return req;
|
this.typeMachineComponentRequirements.push(req);
|
||||||
});
|
return req;
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pieceRequirements: TypeMachinePieceRequirementRecord[] = [];
|
let pieceRequirements: TypeMachinePieceRequirementRecord[] = [];
|
||||||
@@ -417,28 +429,49 @@ class InMemoryPrismaService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.buildTypeMachine(record, include ?? {}, componentRequirements, pieceRequirements);
|
return this.buildTypeMachine(
|
||||||
|
record,
|
||||||
|
include ?? {},
|
||||||
|
componentRequirements,
|
||||||
|
pieceRequirements,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
findUnique: async ({ where, include }: any) => {
|
findUnique: async ({ where, include }: any) => {
|
||||||
const typeMachine = this.typeMachines.find((item) => item.id === where.id);
|
const typeMachine = this.typeMachines.find(
|
||||||
|
(item) => item.id === where.id,
|
||||||
|
);
|
||||||
if (!typeMachine) {
|
if (!typeMachine) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const componentRequirements = this.typeMachineComponentRequirements.filter(
|
const componentRequirements =
|
||||||
(item) => item.typeMachineId === typeMachine.id,
|
this.typeMachineComponentRequirements.filter(
|
||||||
);
|
(item) => item.typeMachineId === typeMachine.id,
|
||||||
|
);
|
||||||
const pieceRequirements = this.typeMachinePieceRequirements.filter(
|
const pieceRequirements = this.typeMachinePieceRequirements.filter(
|
||||||
(item) => item.typeMachineId === typeMachine.id,
|
(item) => item.typeMachineId === typeMachine.id,
|
||||||
);
|
);
|
||||||
return this.buildTypeMachine(typeMachine, include ?? {}, componentRequirements, pieceRequirements);
|
return this.buildTypeMachine(
|
||||||
|
typeMachine,
|
||||||
|
include ?? {},
|
||||||
|
componentRequirements,
|
||||||
|
pieceRequirements,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
findMany: async ({ include }: any = {}) => {
|
findMany: async ({ include }: any = {}) => {
|
||||||
return this.typeMachines.map((item) => {
|
return this.typeMachines.map((item) => {
|
||||||
const componentRequirements = this.typeMachineComponentRequirements.filter(
|
const componentRequirements =
|
||||||
|
this.typeMachineComponentRequirements.filter(
|
||||||
|
(req) => req.typeMachineId === item.id,
|
||||||
|
);
|
||||||
|
const pieceRequirements = this.typeMachinePieceRequirements.filter(
|
||||||
(req) => req.typeMachineId === item.id,
|
(req) => req.typeMachineId === item.id,
|
||||||
);
|
);
|
||||||
const pieceRequirements = this.typeMachinePieceRequirements.filter((req) => req.typeMachineId === item.id);
|
return this.buildTypeMachine(
|
||||||
return this.buildTypeMachine(item, include ?? {}, componentRequirements, pieceRequirements);
|
item,
|
||||||
|
include ?? {},
|
||||||
|
componentRequirements,
|
||||||
|
pieceRequirements,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -471,9 +504,13 @@ class InMemoryPrismaService {
|
|||||||
findMany: async ({ include, where }: any = {}) => {
|
findMany: async ({ include, where }: any = {}) => {
|
||||||
let machines = this.machines;
|
let machines = this.machines;
|
||||||
if (where?.siteId) {
|
if (where?.siteId) {
|
||||||
machines = machines.filter((machine) => machine.siteId === where.siteId);
|
machines = machines.filter(
|
||||||
|
(machine) => machine.siteId === where.siteId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return machines.map((machine) => this.buildMachine(machine, include ?? {}));
|
return machines.map((machine) =>
|
||||||
|
this.buildMachine(machine, include ?? {}),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
delete: async ({ where }: any) => {
|
delete: async ({ where }: any) => {
|
||||||
const index = this.machines.findIndex((item) => item.id === where.id);
|
const index = this.machines.findIndex((item) => item.id === where.id);
|
||||||
@@ -498,7 +535,8 @@ class InMemoryPrismaService {
|
|||||||
parentComposantId: data.parentComposantId ?? null,
|
parentComposantId: data.parentComposantId ?? null,
|
||||||
typeComposantId: data.typeComposantId ?? null,
|
typeComposantId: data.typeComposantId ?? null,
|
||||||
composantModelId: data.composantModelId ?? null,
|
composantModelId: data.composantModelId ?? null,
|
||||||
typeMachineComponentRequirementId: data.typeMachineComponentRequirementId ?? null,
|
typeMachineComponentRequirementId:
|
||||||
|
data.typeMachineComponentRequirementId ?? null,
|
||||||
constructeurId: data.constructeurId ?? null,
|
constructeurId: data.constructeurId ?? null,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
@@ -509,10 +547,14 @@ class InMemoryPrismaService {
|
|||||||
findMany: async ({ where }: any) => {
|
findMany: async ({ where }: any) => {
|
||||||
let composants = this.composants;
|
let composants = this.composants;
|
||||||
if (where?.machineId !== undefined) {
|
if (where?.machineId !== undefined) {
|
||||||
composants = composants.filter((item) => item.machineId === where.machineId);
|
composants = composants.filter(
|
||||||
|
(item) => item.machineId === where.machineId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (where?.parentComposantId !== undefined) {
|
if (where?.parentComposantId !== undefined) {
|
||||||
composants = composants.filter((item) => item.parentComposantId === where.parentComposantId);
|
composants = composants.filter(
|
||||||
|
(item) => item.parentComposantId === where.parentComposantId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return composants.map((item) => ({ ...item }));
|
return composants.map((item) => ({ ...item }));
|
||||||
},
|
},
|
||||||
@@ -531,7 +573,8 @@ class InMemoryPrismaService {
|
|||||||
composantId: data.composantId ?? null,
|
composantId: data.composantId ?? null,
|
||||||
typePieceId: data.typePieceId ?? null,
|
typePieceId: data.typePieceId ?? null,
|
||||||
pieceModelId: data.pieceModelId ?? null,
|
pieceModelId: data.pieceModelId ?? null,
|
||||||
typeMachinePieceRequirementId: data.typeMachinePieceRequirementId ?? null,
|
typeMachinePieceRequirementId:
|
||||||
|
data.typeMachinePieceRequirementId ?? null,
|
||||||
constructeurId: data.constructeurId ?? null,
|
constructeurId: data.constructeurId ?? null,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
@@ -545,7 +588,9 @@ class InMemoryPrismaService {
|
|||||||
pieces = pieces.filter((item) => item.machineId === where.machineId);
|
pieces = pieces.filter((item) => item.machineId === where.machineId);
|
||||||
}
|
}
|
||||||
if (where?.composantId !== undefined) {
|
if (where?.composantId !== undefined) {
|
||||||
pieces = pieces.filter((item) => item.composantId === where.composantId);
|
pieces = pieces.filter(
|
||||||
|
(item) => item.composantId === where.composantId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return pieces.map((item) => ({ ...item }));
|
return pieces.map((item) => ({ ...item }));
|
||||||
},
|
},
|
||||||
@@ -574,14 +619,18 @@ class InMemoryPrismaService {
|
|||||||
return this.customFields
|
return this.customFields
|
||||||
.filter((field) => {
|
.filter((field) => {
|
||||||
if (!where) return true;
|
if (!where) return true;
|
||||||
return Object.entries(where).every(([key, value]) => (field as any)[key] === value);
|
return Object.entries(where).every(
|
||||||
|
([key, value]) => (field as any)[key] === value,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.map((field) => ({ ...field }));
|
.map((field) => ({ ...field }));
|
||||||
},
|
},
|
||||||
deleteMany: async ({ where }: any) => {
|
deleteMany: async ({ where }: any) => {
|
||||||
const before = this.customFields.length;
|
const before = this.customFields.length;
|
||||||
this.customFields = this.customFields.filter((field) => {
|
this.customFields = this.customFields.filter((field) => {
|
||||||
return !Object.entries(where).every(([key, value]) => (field as any)[key] === value);
|
return !Object.entries(where).every(
|
||||||
|
([key, value]) => (field as any)[key] === value,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return { count: before - this.customFields.length };
|
return { count: before - this.customFields.length };
|
||||||
},
|
},
|
||||||
@@ -606,12 +655,18 @@ class InMemoryPrismaService {
|
|||||||
findMany: async ({ where, include }: any) => {
|
findMany: async ({ where, include }: any) => {
|
||||||
const records = this.customFieldValues.filter((value) => {
|
const records = this.customFieldValues.filter((value) => {
|
||||||
if (!where) return true;
|
if (!where) return true;
|
||||||
return Object.entries(where).every(([key, v]) => (value as any)[key] === v);
|
return Object.entries(where).every(
|
||||||
|
([key, v]) => (value as any)[key] === v,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return records.map((record) => this.buildCustomFieldValue(record, include ?? {}));
|
return records.map((record) =>
|
||||||
|
this.buildCustomFieldValue(record, include ?? {}),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
findUnique: async ({ where, include }: any) => {
|
findUnique: async ({ where, include }: any) => {
|
||||||
const record = this.customFieldValues.find((value) => value.id === where.id);
|
const record = this.customFieldValues.find(
|
||||||
|
(value) => value.id === where.id,
|
||||||
|
);
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -625,7 +680,9 @@ class InMemoryPrismaService {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
update: async ({ where, data, include }: any) => {
|
update: async ({ where, data, include }: any) => {
|
||||||
const record = this.customFieldValues.find((value) => value.id === where.id);
|
const record = this.customFieldValues.find(
|
||||||
|
(value) => value.id === where.id,
|
||||||
|
);
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new Error('Custom field value not found');
|
throw new Error('Custom field value not found');
|
||||||
}
|
}
|
||||||
@@ -636,7 +693,9 @@ class InMemoryPrismaService {
|
|||||||
return this.buildCustomFieldValue(record, include ?? {});
|
return this.buildCustomFieldValue(record, include ?? {});
|
||||||
},
|
},
|
||||||
delete: async ({ where }: any) => {
|
delete: async ({ where }: any) => {
|
||||||
const index = this.customFieldValues.findIndex((value) => value.id === where.id);
|
const index = this.customFieldValues.findIndex(
|
||||||
|
(value) => value.id === where.id,
|
||||||
|
);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
throw new Error('Custom field value not found');
|
throw new Error('Custom field value not found');
|
||||||
}
|
}
|
||||||
@@ -649,24 +708,32 @@ class InMemoryPrismaService {
|
|||||||
count: async ({ where }: any) => {
|
count: async ({ where }: any) => {
|
||||||
return this.profiles.filter((profile) => {
|
return this.profiles.filter((profile) => {
|
||||||
if (!where) return true;
|
if (!where) return true;
|
||||||
return Object.entries(where).every(([key, value]) => (profile as any)[key] === value);
|
return Object.entries(where).every(
|
||||||
|
([key, value]) => (profile as any)[key] === value,
|
||||||
|
);
|
||||||
}).length;
|
}).length;
|
||||||
},
|
},
|
||||||
findMany: async ({ where, orderBy, select }: any) => {
|
findMany: async ({ where, orderBy, select }: any) => {
|
||||||
let profiles = this.profiles;
|
let profiles = this.profiles;
|
||||||
if (where) {
|
if (where) {
|
||||||
profiles = profiles.filter((profile) =>
|
profiles = profiles.filter((profile) =>
|
||||||
Object.entries(where).every(([key, value]) => (profile as any)[key] === value),
|
Object.entries(where).every(
|
||||||
|
([key, value]) => (profile as any)[key] === value,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (orderBy?.createdAt === 'asc') {
|
if (orderBy?.createdAt === 'asc') {
|
||||||
profiles = [...profiles].sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
profiles = [...profiles].sort(
|
||||||
|
(a, b) => a.createdAt.getTime() - b.createdAt.getTime(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return profiles.map((profile) => this.applySelect(profile, select));
|
return profiles.map((profile) => this.applySelect(profile, select));
|
||||||
},
|
},
|
||||||
findFirst: async ({ where, select }: any) => {
|
findFirst: async ({ where, select }: any) => {
|
||||||
const profile = this.profiles.find((item) =>
|
const profile = this.profiles.find((item) =>
|
||||||
Object.entries(where).every(([key, value]) => (item as any)[key] === value),
|
Object.entries(where).every(
|
||||||
|
([key, value]) => (item as any)[key] === value,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return profile ? this.applySelect(profile, select) : null;
|
return profile ? this.applySelect(profile, select) : null;
|
||||||
},
|
},
|
||||||
@@ -713,8 +780,12 @@ class InMemoryPrismaService {
|
|||||||
private buildSite(site: SiteRecord, include: any) {
|
private buildSite(site: SiteRecord, include: any) {
|
||||||
const base: any = { ...site };
|
const base: any = { ...site };
|
||||||
if (include?.machines) {
|
if (include?.machines) {
|
||||||
const machines = this.machines.filter((machine) => machine.siteId === site.id);
|
const machines = this.machines.filter(
|
||||||
base.machines = machines.map((machine) => this.buildMachine(machine, include.machines.include ?? {}));
|
(machine) => machine.siteId === site.id,
|
||||||
|
);
|
||||||
|
base.machines = machines.map((machine) =>
|
||||||
|
this.buildMachine(machine, include.machines.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (include?.documents) {
|
if (include?.documents) {
|
||||||
base.documents = [];
|
base.documents = [];
|
||||||
@@ -730,13 +801,17 @@ class InMemoryPrismaService {
|
|||||||
) {
|
) {
|
||||||
const base: any = { ...record };
|
const base: any = { ...record };
|
||||||
if (include?.customFields) {
|
if (include?.customFields) {
|
||||||
base.customFields = this.customFields.filter((field) => field.typeMachineId === record.id);
|
base.customFields = this.customFields.filter(
|
||||||
|
(field) => field.typeMachineId === record.id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (include?.componentRequirements) {
|
if (include?.componentRequirements) {
|
||||||
base.componentRequirements = componentRequirements.map((requirement) => ({
|
base.componentRequirements = componentRequirements.map((requirement) => ({
|
||||||
...requirement,
|
...requirement,
|
||||||
typeComposant: include.componentRequirements.include?.typeComposant
|
typeComposant: include.componentRequirements.include?.typeComposant
|
||||||
? this.typeComposants.find((item) => item.id === requirement.typeComposantId) ?? null
|
? (this.typeComposants.find(
|
||||||
|
(item) => item.id === requirement.typeComposantId,
|
||||||
|
) ?? null)
|
||||||
: undefined,
|
: undefined,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -744,14 +819,18 @@ class InMemoryPrismaService {
|
|||||||
base.pieceRequirements = pieceRequirements.map((requirement) => ({
|
base.pieceRequirements = pieceRequirements.map((requirement) => ({
|
||||||
...requirement,
|
...requirement,
|
||||||
typePiece: include.pieceRequirements.include?.typePiece
|
typePiece: include.pieceRequirements.include?.typePiece
|
||||||
? this.typePieces.find((item) => item.id === requirement.typePieceId) ?? null
|
? (this.typePieces.find(
|
||||||
|
(item) => item.id === requirement.typePieceId,
|
||||||
|
) ?? null)
|
||||||
: undefined,
|
: undefined,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (include?.machines) {
|
if (include?.machines) {
|
||||||
base.machines = this.machines
|
base.machines = this.machines
|
||||||
.filter((machine) => machine.typeMachineId === record.id)
|
.filter((machine) => machine.typeMachineId === record.id)
|
||||||
.map((machine) => this.buildMachine(machine, include.machines.include ?? {}));
|
.map((machine) =>
|
||||||
|
this.buildMachine(machine, include.machines.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
@@ -768,9 +847,10 @@ class InMemoryPrismaService {
|
|||||||
? this.typeMachines.find((item) => item.id === machine.typeMachineId)
|
? this.typeMachines.find((item) => item.id === machine.typeMachineId)
|
||||||
: null;
|
: null;
|
||||||
if (typeMachine) {
|
if (typeMachine) {
|
||||||
const componentRequirements = this.typeMachineComponentRequirements.filter(
|
const componentRequirements =
|
||||||
(req) => req.typeMachineId === typeMachine.id,
|
this.typeMachineComponentRequirements.filter(
|
||||||
);
|
(req) => req.typeMachineId === typeMachine.id,
|
||||||
|
);
|
||||||
const pieceRequirements = this.typeMachinePieceRequirements.filter(
|
const pieceRequirements = this.typeMachinePieceRequirements.filter(
|
||||||
(req) => req.typeMachineId === typeMachine.id,
|
(req) => req.typeMachineId === typeMachine.id,
|
||||||
);
|
);
|
||||||
@@ -790,20 +870,35 @@ class InMemoryPrismaService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (include?.composants) {
|
if (include?.composants) {
|
||||||
const composants = this.composants.filter((component) => component.machineId === machine.id);
|
const composants = this.composants.filter(
|
||||||
|
(component) => component.machineId === machine.id,
|
||||||
|
);
|
||||||
base.composants = composants
|
base.composants = composants
|
||||||
.filter((component) => component.parentComposantId === null)
|
.filter((component) => component.parentComposantId === null)
|
||||||
.map((component) => this.buildComponent(component, include.composants.include ?? {}));
|
.map((component) =>
|
||||||
|
this.buildComponent(component, include.composants.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.pieces) {
|
if (include?.pieces) {
|
||||||
const machinePieces = this.pieces.filter((piece) => piece.machineId === machine.id && piece.composantId === null);
|
const machinePieces = this.pieces.filter(
|
||||||
base.pieces = machinePieces.map((piece) => this.buildPiece(piece, include.pieces.include ?? {}));
|
(piece) => piece.machineId === machine.id && piece.composantId === null,
|
||||||
|
);
|
||||||
|
base.pieces = machinePieces.map((piece) =>
|
||||||
|
this.buildPiece(piece, include.pieces.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.customFieldValues) {
|
if (include?.customFieldValues) {
|
||||||
const values = this.customFieldValues.filter((value) => value.machineId === machine.id);
|
const values = this.customFieldValues.filter(
|
||||||
base.customFieldValues = values.map((value) => this.buildCustomFieldValue(value, include.customFieldValues.include ?? {}));
|
(value) => value.machineId === machine.id,
|
||||||
|
);
|
||||||
|
base.customFieldValues = values.map((value) =>
|
||||||
|
this.buildCustomFieldValue(
|
||||||
|
value,
|
||||||
|
include.customFieldValues.include ?? {},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.documents) {
|
if (include?.documents) {
|
||||||
@@ -818,7 +913,9 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typeComposant) {
|
if (include?.typeComposant) {
|
||||||
base.typeComposant = component.typeComposantId
|
base.typeComposant = component.typeComposantId
|
||||||
? this.typeComposants.find((item) => item.id === component.typeComposantId) ?? null
|
? (this.typeComposants.find(
|
||||||
|
(item) => item.id === component.typeComposantId,
|
||||||
|
) ?? null)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,26 +925,42 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typeMachineComponentRequirement) {
|
if (include?.typeMachineComponentRequirement) {
|
||||||
const requirement = component.typeMachineComponentRequirementId
|
const requirement = component.typeMachineComponentRequirementId
|
||||||
? this.typeMachineComponentRequirements.find((item) => item.id === component.typeMachineComponentRequirementId) ?? null
|
? (this.typeMachineComponentRequirements.find(
|
||||||
|
(item) => item.id === component.typeMachineComponentRequirementId,
|
||||||
|
) ?? null)
|
||||||
: null;
|
: null;
|
||||||
base.typeMachineComponentRequirement = requirement
|
base.typeMachineComponentRequirement = requirement
|
||||||
? {
|
? {
|
||||||
...requirement,
|
...requirement,
|
||||||
typeComposant: include.typeMachineComponentRequirement.include?.typeComposant
|
typeComposant: include.typeMachineComponentRequirement.include
|
||||||
? this.typeComposants.find((item) => item.id === requirement.typeComposantId) ?? null
|
?.typeComposant
|
||||||
|
? (this.typeComposants.find(
|
||||||
|
(item) => item.id === requirement.typeComposantId,
|
||||||
|
) ?? null)
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.sousComposants) {
|
if (include?.sousComposants) {
|
||||||
const children = this.composants.filter((item) => item.parentComposantId === component.id);
|
const children = this.composants.filter(
|
||||||
base.sousComposants = children.map((child) => this.buildComponent(child, include.sousComposants.include ?? {}));
|
(item) => item.parentComposantId === component.id,
|
||||||
|
);
|
||||||
|
base.sousComposants = children.map((child) =>
|
||||||
|
this.buildComponent(child, include.sousComposants.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.customFieldValues) {
|
if (include?.customFieldValues) {
|
||||||
const values = this.customFieldValues.filter((value) => value.composantId === component.id);
|
const values = this.customFieldValues.filter(
|
||||||
base.customFieldValues = values.map((value) => this.buildCustomFieldValue(value, include.customFieldValues.include ?? {}));
|
(value) => value.composantId === component.id,
|
||||||
|
);
|
||||||
|
base.customFieldValues = values.map((value) =>
|
||||||
|
this.buildCustomFieldValue(
|
||||||
|
value,
|
||||||
|
include.customFieldValues.include ?? {},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.constructeur) {
|
if (include?.constructeur) {
|
||||||
@@ -855,8 +968,12 @@ class InMemoryPrismaService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (include?.pieces) {
|
if (include?.pieces) {
|
||||||
const relatedPieces = this.pieces.filter((piece) => piece.composantId === component.id);
|
const relatedPieces = this.pieces.filter(
|
||||||
base.pieces = relatedPieces.map((piece) => this.buildPiece(piece, include.pieces.include ?? {}));
|
(piece) => piece.composantId === component.id,
|
||||||
|
);
|
||||||
|
base.pieces = relatedPieces.map((piece) =>
|
||||||
|
this.buildPiece(piece, include.pieces.include ?? {}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
@@ -866,8 +983,15 @@ class InMemoryPrismaService {
|
|||||||
const base: any = { ...piece };
|
const base: any = { ...piece };
|
||||||
|
|
||||||
if (include?.customFieldValues) {
|
if (include?.customFieldValues) {
|
||||||
const values = this.customFieldValues.filter((value) => value.pieceId === piece.id);
|
const values = this.customFieldValues.filter(
|
||||||
base.customFieldValues = values.map((value) => this.buildCustomFieldValue(value, include.customFieldValues.include ?? {}));
|
(value) => value.pieceId === piece.id,
|
||||||
|
);
|
||||||
|
base.customFieldValues = values.map((value) =>
|
||||||
|
this.buildCustomFieldValue(
|
||||||
|
value,
|
||||||
|
include.customFieldValues.include ?? {},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.constructeur) {
|
if (include?.constructeur) {
|
||||||
@@ -880,13 +1004,17 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typeMachinePieceRequirement) {
|
if (include?.typeMachinePieceRequirement) {
|
||||||
const requirement = piece.typeMachinePieceRequirementId
|
const requirement = piece.typeMachinePieceRequirementId
|
||||||
? this.typeMachinePieceRequirements.find((item) => item.id === piece.typeMachinePieceRequirementId) ?? null
|
? (this.typeMachinePieceRequirements.find(
|
||||||
|
(item) => item.id === piece.typeMachinePieceRequirementId,
|
||||||
|
) ?? null)
|
||||||
: null;
|
: null;
|
||||||
base.typeMachinePieceRequirement = requirement
|
base.typeMachinePieceRequirement = requirement
|
||||||
? {
|
? {
|
||||||
...requirement,
|
...requirement,
|
||||||
typePiece: include.typeMachinePieceRequirement.include?.typePiece
|
typePiece: include.typeMachinePieceRequirement.include?.typePiece
|
||||||
? this.typePieces.find((item) => item.id === requirement.typePieceId) ?? null
|
? (this.typePieces.find(
|
||||||
|
(item) => item.id === requirement.typePieceId,
|
||||||
|
) ?? null)
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
@@ -894,7 +1022,8 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typePiece) {
|
if (include?.typePiece) {
|
||||||
base.typePiece = piece.typePieceId
|
base.typePiece = piece.typePieceId
|
||||||
? this.typePieces.find((item) => item.id === piece.typePieceId) ?? null
|
? (this.typePieces.find((item) => item.id === piece.typePieceId) ??
|
||||||
|
null)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,7 +1033,9 @@ class InMemoryPrismaService {
|
|||||||
private buildCustomFieldValue(record: CustomFieldValueRecord, include: any) {
|
private buildCustomFieldValue(record: CustomFieldValueRecord, include: any) {
|
||||||
const base: any = { ...record };
|
const base: any = { ...record };
|
||||||
if (include?.customField) {
|
if (include?.customField) {
|
||||||
base.customField = this.customFields.find((field) => field.id === record.customFieldId) ?? null;
|
base.customField =
|
||||||
|
this.customFields.find((field) => field.id === record.customFieldId) ??
|
||||||
|
null;
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
@@ -918,7 +1049,6 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
prismaStub = new InMemoryPrismaService();
|
prismaStub = new InMemoryPrismaService();
|
||||||
|
|
||||||
|
|
||||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
})
|
})
|
||||||
@@ -945,14 +1075,16 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create a type, create a machine with new component/piece selections, and edit technical fields', async () => {
|
it('should create a type, create a machine with new component/piece selections, and edit technical fields', async () => {
|
||||||
const siteResponse = await request(app.getHttpServer()).post('/sites').send({
|
const siteResponse = await request(app.getHttpServer())
|
||||||
name: 'Site Principal',
|
.post('/sites')
|
||||||
contactName: 'Responsable Maintenance',
|
.send({
|
||||||
contactPhone: '+33 1 23 45 67 89',
|
name: 'Site Principal',
|
||||||
contactAddress: '1 rue de la Paix',
|
contactName: 'Responsable Maintenance',
|
||||||
contactPostalCode: '75000',
|
contactPhone: '+33 1 23 45 67 89',
|
||||||
contactCity: 'Paris',
|
contactAddress: '1 rue de la Paix',
|
||||||
});
|
contactPostalCode: '75000',
|
||||||
|
contactCity: 'Paris',
|
||||||
|
});
|
||||||
|
|
||||||
expect(siteResponse.status).toBe(201);
|
expect(siteResponse.status).toBe(201);
|
||||||
const siteId = siteResponse.body.id;
|
const siteId = siteResponse.body.id;
|
||||||
@@ -1069,7 +1201,9 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
expect(machineResponse.status).toBe(201);
|
expect(machineResponse.status).toBe(201);
|
||||||
const machineId = machineResponse.body.id;
|
const machineId = machineResponse.body.id;
|
||||||
|
|
||||||
const machineDetailsResponse = await request(app.getHttpServer()).get(`/machines/${machineId}`);
|
const machineDetailsResponse = await request(app.getHttpServer()).get(
|
||||||
|
`/machines/${machineId}`,
|
||||||
|
);
|
||||||
expect(machineDetailsResponse.status).toBe(200);
|
expect(machineDetailsResponse.status).toBe(200);
|
||||||
const machine = machineDetailsResponse.body;
|
const machine = machineDetailsResponse.body;
|
||||||
|
|
||||||
@@ -1092,7 +1226,9 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
expect(updateResponse.status).toBe(200);
|
expect(updateResponse.status).toBe(200);
|
||||||
expect(updateResponse.body.value).toBe('8 kW');
|
expect(updateResponse.body.value).toBe('8 kW');
|
||||||
|
|
||||||
const refreshedMachineResponse = await request(app.getHttpServer()).get(`/machines/${machine.id}`);
|
const refreshedMachineResponse = await request(app.getHttpServer()).get(
|
||||||
|
`/machines/${machine.id}`,
|
||||||
|
);
|
||||||
expect(refreshedMachineResponse.status).toBe(200);
|
expect(refreshedMachineResponse.status).toBe(200);
|
||||||
const refreshedComponent = refreshedMachineResponse.body.composants[0];
|
const refreshedComponent = refreshedMachineResponse.body.composants[0];
|
||||||
expect(refreshedComponent.customFieldValues[0].value).toBe('8 kW');
|
expect(refreshedComponent.customFieldValues[0].value).toBe('8 kW');
|
||||||
@@ -1110,7 +1246,9 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
const created = { id: 'component-1' };
|
const created = { id: 'component-1' };
|
||||||
const createSpy = jest.spyOn(prisma.composant, 'create').mockResolvedValue(created as any);
|
const createSpy = jest
|
||||||
|
.spyOn(prisma.composant, 'create')
|
||||||
|
.mockResolvedValue(created as any);
|
||||||
|
|
||||||
const response = await request(app.getHttpServer())
|
const response = await request(app.getHttpServer())
|
||||||
.post('/composants')
|
.post('/composants')
|
||||||
@@ -1157,14 +1295,14 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
jest.spyOn(prisma.machine, 'findUnique').mockResolvedValue({
|
jest.spyOn(prisma.machine, 'findUnique').mockResolvedValue({
|
||||||
id: 'machine-1',
|
id: 'machine-1',
|
||||||
typeMachine: {
|
typeMachine: {
|
||||||
pieceRequirements: [
|
pieceRequirements: [{ id: 'req-1', typePieceId: 'type-piece-1' }],
|
||||||
{ id: 'req-1', typePieceId: 'type-piece-1' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
const created = { id: 'piece-1' };
|
const created = { id: 'piece-1' };
|
||||||
const createSpy = jest.spyOn(prisma.piece, 'create').mockResolvedValue(created as any);
|
const createSpy = jest
|
||||||
|
.spyOn(prisma.piece, 'create')
|
||||||
|
.mockResolvedValue(created as any);
|
||||||
|
|
||||||
const response = await request(app.getHttpServer())
|
const response = await request(app.getHttpServer())
|
||||||
.post('/pieces')
|
.post('/pieces')
|
||||||
@@ -1184,9 +1322,7 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
jest.spyOn(prisma.machine, 'findUnique').mockResolvedValue({
|
jest.spyOn(prisma.machine, 'findUnique').mockResolvedValue({
|
||||||
id: 'machine-1',
|
id: 'machine-1',
|
||||||
typeMachine: {
|
typeMachine: {
|
||||||
pieceRequirements: [
|
pieceRequirements: [{ id: 'req-1', typePieceId: 'type-piece-1' }],
|
||||||
{ id: 'req-1', typePieceId: 'type-piece-1' },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
@@ -1203,7 +1339,6 @@ describe('Inventory flow (e2e)', () => {
|
|||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
||||||
expect(createSpy).not.toHaveBeenCalled();
|
expect(createSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user