feat: add product domain and machine integration

- extend Prisma schema with products, product constructs and link tables\n- introduce product service, DTOs and includes with constructeur support\n- integrate product selections across model type skeletons, composants, pièces and machines\n- validate product requirements when building machine skeletons and payloads
This commit is contained in:
Matthieu
2025-11-05 15:34:42 +01:00
parent e81f71e3e7
commit 6cf2b566ce
38 changed files with 2601 additions and 120 deletions

View File

@@ -0,0 +1,75 @@
-- AlterEnum
ALTER TYPE "ModelCategory" ADD VALUE IF NOT EXISTS 'PRODUCT';
-- AlterTable
ALTER TABLE "ModelType" ADD COLUMN "productSkeleton" JSONB;
ALTER TABLE "composants" ADD COLUMN "productId" TEXT;
ALTER TABLE "pieces" ADD COLUMN "productId" TEXT;
ALTER TABLE "documents" ADD COLUMN "productId" TEXT;
ALTER TABLE "custom_fields" ADD COLUMN "typeProductId" TEXT;
ALTER TABLE "custom_field_values" ADD COLUMN "productId" TEXT;
-- CreateTable
CREATE TABLE "products" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"reference" TEXT,
"supplierPrice" DECIMAL(10,2),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"typeProductId" TEXT,
CONSTRAINT "products_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "type_machine_product_requirements" (
"id" TEXT NOT NULL,
"label" TEXT,
"minCount" INTEGER NOT NULL DEFAULT 0,
"maxCount" INTEGER,
"required" BOOLEAN NOT NULL DEFAULT false,
"allowNewModels" BOOLEAN NOT NULL DEFAULT true,
"orderIndex" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"typeMachineId" TEXT NOT NULL,
"typeProductId" TEXT NOT NULL,
CONSTRAINT "type_machine_product_requirements_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "_ProductConstructeurs" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "products_name_key" ON "products"("name");
CREATE UNIQUE INDEX "_ProductConstructeurs_AB_unique" ON "_ProductConstructeurs"("A", "B");
CREATE INDEX "_ProductConstructeurs_B_index" ON "_ProductConstructeurs"("B");
-- AddForeignKey
ALTER TABLE "products" ADD CONSTRAINT "products_typeProductId_fkey" FOREIGN KEY ("typeProductId") REFERENCES "ModelType"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "composants" ADD CONSTRAINT "composants_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "pieces" ADD CONSTRAINT "pieces_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "documents" ADD CONSTRAINT "documents_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "custom_fields" ADD CONSTRAINT "custom_fields_typeProductId_fkey" FOREIGN KEY ("typeProductId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "custom_field_values" ADD CONSTRAINT "custom_field_values_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "type_machine_product_requirements" ADD CONSTRAINT "type_machine_product_requirements_typeMachineId_fkey" FOREIGN KEY ("typeMachineId") REFERENCES "type_machines"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "type_machine_product_requirements" ADD CONSTRAINT "type_machine_product_requirements_typeProductId_fkey" FOREIGN KEY ("typeProductId") REFERENCES "ModelType"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_ProductConstructeurs" ADD CONSTRAINT "_ProductConstructeurs_A_fkey" FOREIGN KEY ("A") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "_ProductConstructeurs" ADD CONSTRAINT "_ProductConstructeurs_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,26 @@
-- CreateTable
CREATE TABLE "machine_product_links" (
"id" TEXT NOT NULL,
"machineId" TEXT NOT NULL,
"productId" TEXT NOT NULL,
"typeMachineProductRequirementId" TEXT,
"parentLinkId" TEXT,
"parentComponentLinkId" TEXT,
"parentPieceLinkId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "machine_product_links_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_machineId_fkey" FOREIGN KEY ("machineId") REFERENCES "machines"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_typeMachineProductRequirementId_fkey" FOREIGN KEY ("typeMachineProductRequirementId") REFERENCES "type_machine_product_requirements"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_parentLinkId_fkey" FOREIGN KEY ("parentLinkId") REFERENCES "machine_product_links"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_parentComponentLinkId_fkey" FOREIGN KEY ("parentComponentLinkId") REFERENCES "machine_component_links"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "machine_product_links" ADD CONSTRAINT "machine_product_links_parentPieceLinkId_fkey" FOREIGN KEY ("parentPieceLinkId") REFERENCES "machine_piece_links"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateIndex
CREATE INDEX "machine_product_links_machineId_idx" ON "machine_product_links"("machineId");
CREATE INDEX "machine_product_links_productId_idx" ON "machine_product_links"("productId");

View File

@@ -47,6 +47,7 @@ model TypeMachine {
customFields CustomField[] @relation("TypeMachineCustomFields")
componentRequirements TypeMachineComponentRequirement[]
pieceRequirements TypeMachinePieceRequirement[]
productRequirements TypeMachineProductRequirement[]
@@map("type_machines")
}
@@ -70,6 +71,7 @@ model Machine {
componentLinks MachineComponentLink[]
pieceLinks MachinePieceLink[]
productLinks MachineProductLink[]
documents Document[] @relation("MachineDocuments")
customFieldValues CustomFieldValue[] @relation("MachineCustomFieldValues")
@@ -88,6 +90,9 @@ model Composant {
typeComposantId String?
typeComposant ModelType? @relation("ModelTypeComponentAssignments", fields: [typeComposantId], references: [id])
productId String?
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
constructeurs Constructeur[] @relation("ComposantConstructeurs")
documents Document[] @relation("ComposantDocuments")
@@ -108,6 +113,9 @@ model Piece {
typePieceId String?
typePiece ModelType? @relation("ModelTypePieceAssignments", fields: [typePieceId], references: [id])
productId String?
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
constructeurs Constructeur[] @relation("PieceConstructeurs")
documents Document[] @relation("PieceDocuments")
@@ -117,6 +125,27 @@ model Piece {
@@map("pieces")
}
model Product {
id String @id @default(cuid())
name String @unique
reference String?
supplierPrice Decimal? @db.Decimal(10, 2)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
typeProductId String?
typeProduct ModelType? @relation("ModelTypeProductAssignments", fields: [typeProductId], references: [id])
constructeurs Constructeur[] @relation("ProductConstructeurs")
documents Document[] @relation("ProductDocuments")
customFieldValues CustomFieldValue[] @relation("ProductCustomFieldValues")
pieces Piece[]
composants Composant[]
machineLinks MachineProductLink[]
@@map("products")
}
model MachineComponentLink {
id String @id @default(cuid())
machineId String
@@ -135,6 +164,7 @@ model MachineComponentLink {
childLinks MachineComponentLink[] @relation("MachineComponentLinkHierarchy")
typeMachineComponentRequirement TypeMachineComponentRequirement? @relation("ComponentRequirementLinks", fields: [typeMachineComponentRequirementId], references: [id], onDelete: SetNull)
pieceLinks MachinePieceLink[] @relation("ComponentLinkPieceLinks")
productLinks MachineProductLink[] @relation("ComponentLinkProductLinks")
@@map("machine_component_links")
}
@@ -155,13 +185,37 @@ model MachinePieceLink {
piece Piece @relation(fields: [pieceId], references: [id], onDelete: Cascade)
parentLink MachineComponentLink? @relation("ComponentLinkPieceLinks", fields: [parentLinkId], references: [id], onDelete: Cascade)
typeMachinePieceRequirement TypeMachinePieceRequirement? @relation("PieceRequirementLinks", fields: [typeMachinePieceRequirementId], references: [id], onDelete: SetNull)
productLinks MachineProductLink[] @relation("PieceLinkProductLinks")
@@map("machine_piece_links")
}
model MachineProductLink {
id String @id @default(cuid())
machineId String
productId String
typeMachineProductRequirementId String?
parentLinkId String?
parentComponentLinkId String?
parentPieceLinkId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
typeMachineProductRequirement TypeMachineProductRequirement? @relation("ProductRequirementLinks", fields: [typeMachineProductRequirementId], references: [id], onDelete: SetNull)
parentLink MachineProductLink? @relation("MachineProductLinkHierarchy", fields: [parentLinkId], references: [id], onDelete: Cascade)
childLinks MachineProductLink[] @relation("MachineProductLinkHierarchy")
parentComponentLink MachineComponentLink? @relation("ComponentLinkProductLinks", fields: [parentComponentLinkId], references: [id], onDelete: Cascade)
parentPieceLink MachinePieceLink? @relation("PieceLinkProductLinks", fields: [parentPieceLinkId], references: [id], onDelete: Cascade)
@@map("machine_product_links")
}
enum ModelCategory {
COMPONENT
PIECE
PRODUCT
}
model ModelType {
@@ -173,15 +227,19 @@ model ModelType {
description String? @db.Text
componentSkeleton Json?
pieceSkeleton Json?
productSkeleton Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
composants Composant[] @relation("ModelTypeComponentAssignments")
componentRequirements TypeMachineComponentRequirement[] @relation("ModelTypeComponentRequirements")
customFields CustomField[] @relation("ModelTypeCustomFields")
productCustomFields CustomField[] @relation("ModelTypeProductCustomFields")
pieceRequirements TypeMachinePieceRequirement[] @relation("ModelTypePieceRequirements")
pieces Piece[] @relation("ModelTypePieceAssignments")
pieceCustomFields CustomField[] @relation("ModelTypePieceCustomFields")
products Product[] @relation("ModelTypeProductAssignments")
productRequirements TypeMachineProductRequirement[] @relation("ModelTypeProductRequirements")
@@unique([category, name])
}
@@ -197,6 +255,7 @@ model Constructeur {
machines Machine[] @relation("MachineConstructeurs")
composants Composant[] @relation("ComposantConstructeurs")
pieces Piece[] @relation("PieceConstructeurs")
products Product[] @relation("ProductConstructeurs")
@@map("constructeurs")
}
@@ -232,6 +291,9 @@ model Document {
pieceId String?
piece Piece? @relation("PieceDocuments", fields: [pieceId], references: [id], onDelete: Cascade)
productId String?
product Product? @relation("ProductDocuments", fields: [productId], references: [id], onDelete: Cascade)
siteId String?
site Site? @relation("SiteDocuments", fields: [siteId], references: [id], onDelete: Cascade)
@@ -259,6 +321,9 @@ model CustomField {
typePieceId String?
typePiece ModelType? @relation("ModelTypePieceCustomFields", fields: [typePieceId], references: [id], onDelete: Cascade)
typeProductId String?
typeProduct ModelType? @relation("ModelTypeProductCustomFields", fields: [typeProductId], references: [id], onDelete: Cascade)
// Relations avec les valeurs
customFieldValues CustomFieldValue[]
@@ -284,6 +349,9 @@ model CustomFieldValue {
pieceId String?
piece Piece? @relation("PieceCustomFieldValues", fields: [pieceId], references: [id], onDelete: Cascade)
productId String?
product Product? @relation("ProductCustomFieldValues", fields: [productId], references: [id], onDelete: Cascade)
@@map("custom_field_values")
}
@@ -330,3 +398,24 @@ model TypeMachinePieceRequirement {
@@map("type_machine_piece_requirements")
}
model TypeMachineProductRequirement {
id String @id @default(cuid())
label String?
minCount Int @default(0)
maxCount Int?
required Boolean @default(false)
allowNewModels Boolean @default(true)
orderIndex Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
typeMachineId String
typeMachine TypeMachine @relation(fields: [typeMachineId], references: [id], onDelete: Cascade)
typeProductId String
typeProduct ModelType @relation("ModelTypeProductRequirements", fields: [typeProductId], references: [id])
machineProductLinks MachineProductLink[] @relation("ProductRequirementLinks")
@@map("type_machine_product_requirements")
}