fix: corrige les associations constructeurs
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
-- Convert single constructeur relation to many-to-many for machines, composants et pièces
|
||||||
|
|
||||||
|
-- Machines → Constructeurs
|
||||||
|
ALTER TABLE "machines" DROP CONSTRAINT IF EXISTS "machines_constructeurId_fkey";
|
||||||
|
|
||||||
|
CREATE TABLE "_MachineConstructeurs" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_A_fkey" FOREIGN KEY ("A") REFERENCES "machines"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_MachineConstructeurs_AB_unique" ON "_MachineConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_MachineConstructeurs_B_index" ON "_MachineConstructeurs"("B");
|
||||||
|
|
||||||
|
INSERT INTO "_MachineConstructeurs" ("A", "B")
|
||||||
|
SELECT "id", "constructeurId"
|
||||||
|
FROM "machines"
|
||||||
|
WHERE "constructeurId" IS NOT NULL
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
ALTER TABLE "machines" DROP COLUMN IF EXISTS "constructeurId";
|
||||||
|
|
||||||
|
-- Composants → Constructeurs
|
||||||
|
ALTER TABLE "composants" DROP CONSTRAINT IF EXISTS "composants_constructeurId_fkey";
|
||||||
|
|
||||||
|
CREATE TABLE "_ComposantConstructeurs" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_A_fkey" FOREIGN KEY ("A") REFERENCES "composants"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_ComposantConstructeurs_AB_unique" ON "_ComposantConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_ComposantConstructeurs_B_index" ON "_ComposantConstructeurs"("B");
|
||||||
|
|
||||||
|
INSERT INTO "_ComposantConstructeurs" ("A", "B")
|
||||||
|
SELECT "id", "constructeurId"
|
||||||
|
FROM "composants"
|
||||||
|
WHERE "constructeurId" IS NOT NULL
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
ALTER TABLE "composants" DROP COLUMN IF EXISTS "constructeurId";
|
||||||
|
|
||||||
|
-- Pièces → Constructeurs
|
||||||
|
ALTER TABLE "pieces" DROP CONSTRAINT IF EXISTS "pieces_constructeurId_fkey";
|
||||||
|
|
||||||
|
CREATE TABLE "_PieceConstructeurs" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_PieceConstructeurs_A_fkey" FOREIGN KEY ("A") REFERENCES "pieces"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_PieceConstructeurs_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_PieceConstructeurs_AB_unique" ON "_PieceConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_PieceConstructeurs_B_index" ON "_PieceConstructeurs"("B");
|
||||||
|
|
||||||
|
INSERT INTO "_PieceConstructeurs" ("A", "B")
|
||||||
|
SELECT "id", "constructeurId"
|
||||||
|
FROM "pieces"
|
||||||
|
WHERE "constructeurId" IS NOT NULL
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
ALTER TABLE "pieces" DROP COLUMN IF EXISTS "constructeurId";
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
-- Fix the orientation of implicit many-to-many join tables between constructeurs
|
||||||
|
-- and machines/composants/pièces so that Prisma inserts target IDs into the
|
||||||
|
-- matching foreign key columns.
|
||||||
|
|
||||||
|
-- Machines ↔ Constructeurs
|
||||||
|
CREATE TABLE "_MachineConstructeurs_new" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_new_A_fkey" FOREIGN KEY ("A") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_new_B_fkey" FOREIGN KEY ("B") REFERENCES "machines"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "_MachineConstructeurs_new" ("A", "B")
|
||||||
|
SELECT "B", "A"
|
||||||
|
FROM "_MachineConstructeurs";
|
||||||
|
|
||||||
|
DROP TABLE "_MachineConstructeurs";
|
||||||
|
|
||||||
|
ALTER TABLE "_MachineConstructeurs_new" RENAME TO "_MachineConstructeurs";
|
||||||
|
ALTER TABLE "_MachineConstructeurs" RENAME CONSTRAINT "_MachineConstructeurs_new_A_fkey" TO "_MachineConstructeurs_A_fkey";
|
||||||
|
ALTER TABLE "_MachineConstructeurs" RENAME CONSTRAINT "_MachineConstructeurs_new_B_fkey" TO "_MachineConstructeurs_B_fkey";
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_MachineConstructeurs_AB_unique" ON "_MachineConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_MachineConstructeurs_B_index" ON "_MachineConstructeurs"("B");
|
||||||
|
|
||||||
|
-- Composants ↔ Constructeurs
|
||||||
|
CREATE TABLE "_ComposantConstructeurs_new" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_new_A_fkey" FOREIGN KEY ("A") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_new_B_fkey" FOREIGN KEY ("B") REFERENCES "composants"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "_ComposantConstructeurs_new" ("A", "B")
|
||||||
|
SELECT "B", "A"
|
||||||
|
FROM "_ComposantConstructeurs";
|
||||||
|
|
||||||
|
DROP TABLE "_ComposantConstructeurs";
|
||||||
|
|
||||||
|
ALTER TABLE "_ComposantConstructeurs_new" RENAME TO "_ComposantConstructeurs";
|
||||||
|
ALTER TABLE "_ComposantConstructeurs" RENAME CONSTRAINT "_ComposantConstructeurs_new_A_fkey" TO "_ComposantConstructeurs_A_fkey";
|
||||||
|
ALTER TABLE "_ComposantConstructeurs" RENAME CONSTRAINT "_ComposantConstructeurs_new_B_fkey" TO "_ComposantConstructeurs_B_fkey";
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_ComposantConstructeurs_AB_unique" ON "_ComposantConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_ComposantConstructeurs_B_index" ON "_ComposantConstructeurs"("B");
|
||||||
|
|
||||||
|
-- Pièces ↔ Constructeurs
|
||||||
|
CREATE TABLE "_PieceConstructeurs_new" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_PieceConstructeurs_new_A_fkey" FOREIGN KEY ("A") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_PieceConstructeurs_new_B_fkey" FOREIGN KEY ("B") REFERENCES "pieces"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "_PieceConstructeurs_new" ("A", "B")
|
||||||
|
SELECT "B", "A"
|
||||||
|
FROM "_PieceConstructeurs";
|
||||||
|
|
||||||
|
DROP TABLE "_PieceConstructeurs";
|
||||||
|
|
||||||
|
ALTER TABLE "_PieceConstructeurs_new" RENAME TO "_PieceConstructeurs";
|
||||||
|
ALTER TABLE "_PieceConstructeurs" RENAME CONSTRAINT "_PieceConstructeurs_new_A_fkey" TO "_PieceConstructeurs_A_fkey";
|
||||||
|
ALTER TABLE "_PieceConstructeurs" RENAME CONSTRAINT "_PieceConstructeurs_new_B_fkey" TO "_PieceConstructeurs_B_fkey";
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_PieceConstructeurs_AB_unique" ON "_PieceConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_PieceConstructeurs_B_index" ON "_PieceConstructeurs"("B");
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-- Restore the original orientation of the machine/composant ↔ constructeur
|
||||||
|
-- implicit join tables after the previous corrective migration, while keeping
|
||||||
|
-- the pièce ↔ constructeur table aligned with Prisma's expectations.
|
||||||
|
|
||||||
|
-- Machines ↔ Constructeurs must map column A → machine, B → constructeur
|
||||||
|
CREATE TABLE "_MachineConstructeurs_restored" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_restored_A_fkey" FOREIGN KEY ("A") REFERENCES "machines"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_MachineConstructeurs_restored_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "_MachineConstructeurs_restored" ("A", "B")
|
||||||
|
SELECT "B", "A"
|
||||||
|
FROM "_MachineConstructeurs";
|
||||||
|
|
||||||
|
DROP TABLE "_MachineConstructeurs";
|
||||||
|
|
||||||
|
ALTER TABLE "_MachineConstructeurs_restored" RENAME TO "_MachineConstructeurs";
|
||||||
|
ALTER TABLE "_MachineConstructeurs" RENAME CONSTRAINT "_MachineConstructeurs_restored_A_fkey" TO "_MachineConstructeurs_A_fkey";
|
||||||
|
ALTER TABLE "_MachineConstructeurs" RENAME CONSTRAINT "_MachineConstructeurs_restored_B_fkey" TO "_MachineConstructeurs_B_fkey";
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_MachineConstructeurs_AB_unique" ON "_MachineConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_MachineConstructeurs_B_index" ON "_MachineConstructeurs"("B");
|
||||||
|
|
||||||
|
-- Composants ↔ Constructeurs must map column A → composant, B → constructeur
|
||||||
|
CREATE TABLE "_ComposantConstructeurs_restored" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_restored_A_fkey" FOREIGN KEY ("A") REFERENCES "composants"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_ComposantConstructeurs_restored_B_fkey" FOREIGN KEY ("B") REFERENCES "constructeurs"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "_ComposantConstructeurs_restored" ("A", "B")
|
||||||
|
SELECT "B", "A"
|
||||||
|
FROM "_ComposantConstructeurs";
|
||||||
|
|
||||||
|
DROP TABLE "_ComposantConstructeurs";
|
||||||
|
|
||||||
|
ALTER TABLE "_ComposantConstructeurs_restored" RENAME TO "_ComposantConstructeurs";
|
||||||
|
ALTER TABLE "_ComposantConstructeurs" RENAME CONSTRAINT "_ComposantConstructeurs_restored_A_fkey" TO "_ComposantConstructeurs_A_fkey";
|
||||||
|
ALTER TABLE "_ComposantConstructeurs" RENAME CONSTRAINT "_ComposantConstructeurs_restored_B_fkey" TO "_ComposantConstructeurs_B_fkey";
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "_ComposantConstructeurs_AB_unique" ON "_ComposantConstructeurs"("A", "B");
|
||||||
|
CREATE INDEX "_ComposantConstructeurs_B_index" ON "_ComposantConstructeurs"("B");
|
||||||
@@ -66,8 +66,7 @@ model Machine {
|
|||||||
typeMachineId String?
|
typeMachineId String?
|
||||||
typeMachine TypeMachine? @relation(fields: [typeMachineId], references: [id])
|
typeMachine TypeMachine? @relation(fields: [typeMachineId], references: [id])
|
||||||
|
|
||||||
constructeurId String?
|
constructeurs Constructeur[] @relation("MachineConstructeurs")
|
||||||
constructeur Constructeur? @relation(fields: [constructeurId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
componentLinks MachineComponentLink[]
|
componentLinks MachineComponentLink[]
|
||||||
pieceLinks MachinePieceLink[]
|
pieceLinks MachinePieceLink[]
|
||||||
@@ -89,8 +88,7 @@ model Composant {
|
|||||||
typeComposantId String?
|
typeComposantId String?
|
||||||
typeComposant ModelType? @relation("ModelTypeComponentAssignments", fields: [typeComposantId], references: [id])
|
typeComposant ModelType? @relation("ModelTypeComponentAssignments", fields: [typeComposantId], references: [id])
|
||||||
|
|
||||||
constructeurId String?
|
constructeurs Constructeur[] @relation("ComposantConstructeurs")
|
||||||
constructeur Constructeur? @relation(fields: [constructeurId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
documents Document[] @relation("ComposantDocuments")
|
documents Document[] @relation("ComposantDocuments")
|
||||||
customFieldValues CustomFieldValue[] @relation("ComposantCustomFieldValues")
|
customFieldValues CustomFieldValue[] @relation("ComposantCustomFieldValues")
|
||||||
@@ -110,8 +108,7 @@ model Piece {
|
|||||||
typePieceId String?
|
typePieceId String?
|
||||||
typePiece ModelType? @relation("ModelTypePieceAssignments", fields: [typePieceId], references: [id])
|
typePiece ModelType? @relation("ModelTypePieceAssignments", fields: [typePieceId], references: [id])
|
||||||
|
|
||||||
constructeurId String?
|
constructeurs Constructeur[] @relation("PieceConstructeurs")
|
||||||
constructeur Constructeur? @relation(fields: [constructeurId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
documents Document[] @relation("PieceDocuments")
|
documents Document[] @relation("PieceDocuments")
|
||||||
customFieldValues CustomFieldValue[] @relation("PieceCustomFieldValues")
|
customFieldValues CustomFieldValue[] @relation("PieceCustomFieldValues")
|
||||||
@@ -197,9 +194,9 @@ model Constructeur {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
machines Machine[]
|
machines Machine[] @relation("MachineConstructeurs")
|
||||||
composants Composant[]
|
composants Composant[] @relation("ComposantConstructeurs")
|
||||||
pieces Piece[]
|
pieces Piece[] @relation("PieceConstructeurs")
|
||||||
|
|
||||||
@@map("constructeurs")
|
@@map("constructeurs")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ async function createPiece(options: {
|
|||||||
name: string;
|
name: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
price: number;
|
price: number;
|
||||||
constructeurId?: string | null;
|
constructeurIds?: string[] | null;
|
||||||
typeId: string;
|
typeId: string;
|
||||||
fieldValues: Record<string, string>;
|
fieldValues: Record<string, string>;
|
||||||
}) {
|
}) {
|
||||||
@@ -143,17 +143,35 @@ async function createPiece(options: {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return prisma.piece.create({
|
const constructeurIds = Array.isArray(options.constructeurIds)
|
||||||
data: {
|
? Array.from(
|
||||||
name: options.name,
|
new Set(
|
||||||
reference: options.reference,
|
options.constructeurIds
|
||||||
prix: new Prisma.Decimal(options.price),
|
.filter((value): value is string => typeof value === 'string')
|
||||||
typePieceId: options.typeId,
|
.map((value) => value.trim())
|
||||||
constructeurId: options.constructeurId ?? null,
|
.filter((value) => value.length > 0),
|
||||||
customFieldValues: {
|
),
|
||||||
create: customFieldValues,
|
)
|
||||||
},
|
: [];
|
||||||
|
|
||||||
|
const data: any = {
|
||||||
|
name: options.name,
|
||||||
|
reference: options.reference,
|
||||||
|
prix: new Prisma.Decimal(options.price),
|
||||||
|
typePieceId: options.typeId,
|
||||||
|
customFieldValues: {
|
||||||
|
create: customFieldValues,
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (constructeurIds.length) {
|
||||||
|
data.constructeurs = {
|
||||||
|
connect: constructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return prisma.piece.create({
|
||||||
|
data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +179,7 @@ async function createComponent(options: {
|
|||||||
name: string;
|
name: string;
|
||||||
reference: string;
|
reference: string;
|
||||||
price: number;
|
price: number;
|
||||||
constructeurId?: string | null;
|
constructeurIds?: string[] | null;
|
||||||
typeId: string;
|
typeId: string;
|
||||||
fieldValues: Record<string, string>;
|
fieldValues: Record<string, string>;
|
||||||
structure?: Prisma.InputJsonValue;
|
structure?: Prisma.InputJsonValue;
|
||||||
@@ -185,21 +203,39 @@ async function createComponent(options: {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return prisma.composant.create({
|
const constructeurIds = Array.isArray(options.constructeurIds)
|
||||||
data: {
|
? Array.from(
|
||||||
name: options.name,
|
new Set(
|
||||||
reference: options.reference,
|
options.constructeurIds
|
||||||
prix: new Prisma.Decimal(options.price),
|
.filter((value): value is string => typeof value === 'string')
|
||||||
typeComposantId: options.typeId,
|
.map((value) => value.trim())
|
||||||
constructeurId: options.constructeurId ?? null,
|
.filter((value) => value.length > 0),
|
||||||
structure:
|
),
|
||||||
options.structure === undefined
|
)
|
||||||
? Prisma.JsonNull
|
: [];
|
||||||
: options.structure ?? Prisma.JsonNull,
|
|
||||||
customFieldValues: {
|
const data: any = {
|
||||||
create: customFieldValues,
|
name: options.name,
|
||||||
},
|
reference: options.reference,
|
||||||
|
prix: new Prisma.Decimal(options.price),
|
||||||
|
typeComposantId: options.typeId,
|
||||||
|
structure:
|
||||||
|
options.structure === undefined
|
||||||
|
? Prisma.JsonNull
|
||||||
|
: options.structure ?? Prisma.JsonNull,
|
||||||
|
customFieldValues: {
|
||||||
|
create: customFieldValues,
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (constructeurIds.length) {
|
||||||
|
data.constructeurs = {
|
||||||
|
connect: constructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return prisma.composant.create({
|
||||||
|
data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const COMPONENT_WITH_RELATIONS_INCLUDE = {
|
|||||||
customFields: true,
|
customFields: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
customFieldValues: {
|
customFieldValues: {
|
||||||
include: {
|
include: {
|
||||||
customField: { select: CUSTOM_FIELD_SELECT },
|
customField: { select: CUSTOM_FIELD_SELECT },
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { ComposantsService } from './composants.service';
|
import { ComposantsService } from './composants.service';
|
||||||
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';
|
||||||
|
|
||||||
describe('ComposantsService', () => {
|
describe('ComposantsService', () => {
|
||||||
let service: ComposantsService;
|
let service: ComposantsService;
|
||||||
@@ -45,7 +48,10 @@ describe('ComposantsService', () => {
|
|||||||
it('updates a component', async () => {
|
it('updates a component', async () => {
|
||||||
const dto: UpdateComposantDto = { name: 'Updated' };
|
const dto: UpdateComposantDto = { name: 'Updated' };
|
||||||
|
|
||||||
prisma.composant.update.mockResolvedValue({ id: 'comp-1', name: 'Updated' });
|
prisma.composant.update.mockResolvedValue({
|
||||||
|
id: 'comp-1',
|
||||||
|
name: 'Updated',
|
||||||
|
});
|
||||||
|
|
||||||
await service.update('comp-1', dto);
|
await service.update('comp-1', dto);
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import {
|
|||||||
export class ComposantsService {
|
export class ComposantsService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
private buildCreateInput(
|
private async buildCreateInput(
|
||||||
createComposantDto: CreateComposantDto,
|
createComposantDto: CreateComposantDto,
|
||||||
): Prisma.ComposantCreateInput {
|
): Promise<Prisma.ComposantCreateInput> {
|
||||||
const data: Prisma.ComposantCreateInput = {
|
const data: Prisma.ComposantCreateInput = {
|
||||||
name: createComposantDto.name,
|
name: createComposantDto.name,
|
||||||
reference: createComposantDto.reference ?? null,
|
reference: createComposantDto.reference ?? null,
|
||||||
@@ -24,9 +24,14 @@ export class ComposantsService {
|
|||||||
createComposantDto.prix !== undefined ? createComposantDto.prix : null,
|
createComposantDto.prix !== undefined ? createComposantDto.prix : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (createComposantDto.constructeurId) {
|
const constructeurIds = this.normalizeConstructeurIds(
|
||||||
data.constructeur = {
|
createComposantDto.constructeurIds,
|
||||||
connect: { id: createComposantDto.constructeurId },
|
);
|
||||||
|
const resolvedConstructeurIds =
|
||||||
|
await this.resolveExistingConstructeurIds(constructeurIds);
|
||||||
|
if (resolvedConstructeurIds.length) {
|
||||||
|
data.constructeurs = {
|
||||||
|
connect: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +51,7 @@ export class ComposantsService {
|
|||||||
async create(createComposantDto: CreateComposantDto) {
|
async create(createComposantDto: CreateComposantDto) {
|
||||||
try {
|
try {
|
||||||
const created = await this.prisma.composant.create({
|
const created = await this.prisma.composant.create({
|
||||||
data: this.buildCreateInput(createComposantDto),
|
data: await this.buildCreateInput(createComposantDto),
|
||||||
include: COMPONENT_WITH_RELATIONS_INCLUDE,
|
include: COMPONENT_WITH_RELATIONS_INCLUDE,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,10 +90,15 @@ export class ComposantsService {
|
|||||||
data.prix = updateComposantDto.prix;
|
data.prix = updateComposantDto.prix;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateComposantDto.constructeurId !== undefined) {
|
if (updateComposantDto.constructeurIds !== undefined) {
|
||||||
data.constructeur = updateComposantDto.constructeurId
|
const constructeurIds = this.normalizeConstructeurIds(
|
||||||
? { connect: { id: updateComposantDto.constructeurId } }
|
updateComposantDto.constructeurIds,
|
||||||
: { disconnect: true };
|
);
|
||||||
|
const resolvedConstructeurIds =
|
||||||
|
await this.resolveExistingConstructeurIds(constructeurIds);
|
||||||
|
data.constructeurs = {
|
||||||
|
set: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateComposantDto.typeComposantId !== undefined) {
|
if (updateComposantDto.typeComposantId !== undefined) {
|
||||||
@@ -170,6 +180,16 @@ export class ComposantsService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private normalizeConstructeurIds(ids?: string[] | null): string[] {
|
||||||
|
if (!Array.isArray(ids)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const cleaned = ids
|
||||||
|
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
||||||
|
.filter((item) => item.length > 0);
|
||||||
|
return Array.from(new Set(cleaned));
|
||||||
|
}
|
||||||
|
|
||||||
private handlePrismaError(error: unknown): never {
|
private handlePrismaError(error: unknown): never {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
if (error.code === 'P2002' && this.isNameConstraint(error)) {
|
if (error.code === 'P2002' && this.isNameConstraint(error)) {
|
||||||
@@ -190,4 +210,17 @@ export class ComposantsService {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
private async resolveExistingConstructeurIds(
|
||||||
|
ids: string[],
|
||||||
|
): Promise<string[]> {
|
||||||
|
if (!ids.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const existing = await this.prisma.constructeur.findMany({
|
||||||
|
where: { id: { in: ids } },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
const existingIds = new Set(existing.map(({ id }) => id));
|
||||||
|
return ids.filter((id) => existingIds.has(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,10 @@ describe('MachinesService', () => {
|
|||||||
prix: null,
|
prix: null,
|
||||||
createdAt: timestamp,
|
createdAt: timestamp,
|
||||||
updatedAt: timestamp,
|
updatedAt: timestamp,
|
||||||
constructeurId: null,
|
constructeurs: [],
|
||||||
typePieceId: null,
|
typePieceId: null,
|
||||||
documents: [],
|
documents: [],
|
||||||
customFieldValues: [],
|
customFieldValues: [],
|
||||||
constructeur: null,
|
|
||||||
typePiece: null,
|
typePiece: null,
|
||||||
},
|
},
|
||||||
typeMachinePieceRequirement: null,
|
typeMachinePieceRequirement: null,
|
||||||
@@ -81,7 +80,7 @@ describe('MachinesService', () => {
|
|||||||
id: 'piece-root',
|
id: 'piece-root',
|
||||||
name: 'Root piece',
|
name: 'Root piece',
|
||||||
},
|
},
|
||||||
} as any;
|
};
|
||||||
|
|
||||||
const componentChildLink = {
|
const componentChildLink = {
|
||||||
id: 'component-child',
|
id: 'component-child',
|
||||||
@@ -101,11 +100,10 @@ describe('MachinesService', () => {
|
|||||||
prix: null,
|
prix: null,
|
||||||
createdAt: timestamp,
|
createdAt: timestamp,
|
||||||
updatedAt: timestamp,
|
updatedAt: timestamp,
|
||||||
constructeurId: null,
|
constructeurs: [],
|
||||||
typeComposantId: null,
|
typeComposantId: null,
|
||||||
documents: [],
|
documents: [],
|
||||||
customFieldValues: [],
|
customFieldValues: [],
|
||||||
constructeur: null,
|
|
||||||
typeComposant: null,
|
typeComposant: null,
|
||||||
},
|
},
|
||||||
typeMachineComponentRequirement: null,
|
typeMachineComponentRequirement: null,
|
||||||
@@ -125,7 +123,7 @@ describe('MachinesService', () => {
|
|||||||
name: 'Root component',
|
name: 'Root component',
|
||||||
},
|
},
|
||||||
pieceLinks: [componentPieceLink],
|
pieceLinks: [componentPieceLink],
|
||||||
} as any;
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: 'machine-1',
|
id: 'machine-1',
|
||||||
@@ -135,11 +133,10 @@ describe('MachinesService', () => {
|
|||||||
createdAt: timestamp,
|
createdAt: timestamp,
|
||||||
updatedAt: timestamp,
|
updatedAt: timestamp,
|
||||||
typeMachineId: null,
|
typeMachineId: null,
|
||||||
constructeurId: null,
|
constructeurs: [],
|
||||||
siteId: 'site-1',
|
siteId: 'site-1',
|
||||||
site: null,
|
site: null,
|
||||||
typeMachine: null,
|
typeMachine: null,
|
||||||
constructeur: null,
|
|
||||||
componentLinks: [componentRootLink, componentChildLink],
|
componentLinks: [componentRootLink, componentChildLink],
|
||||||
pieceLinks: [rootPieceLink, componentPieceLink],
|
pieceLinks: [rootPieceLink, componentPieceLink],
|
||||||
customFieldValues: [],
|
customFieldValues: [],
|
||||||
@@ -165,9 +162,7 @@ describe('MachinesService', () => {
|
|||||||
expect(rootLink.pieceLinks[0].parent?.overrides.name).toBe(
|
expect(rootLink.pieceLinks[0].parent?.overrides.name).toBe(
|
||||||
'Root component override',
|
'Root component override',
|
||||||
);
|
);
|
||||||
expect(rootLink.pieceLinks[0].originalPiece.name).toBe(
|
expect(rootLink.pieceLinks[0].originalPiece.name).toBe('Piece component');
|
||||||
'Piece component',
|
|
||||||
);
|
|
||||||
expect(rootLink.pieceLinks[0].piece.name).toBe('Component piece name');
|
expect(rootLink.pieceLinks[0].piece.name).toBe('Component piece name');
|
||||||
expect(rootLink.pieceLinks[0].overrides.reference).toBe('CP-001');
|
expect(rootLink.pieceLinks[0].overrides.reference).toBe('CP-001');
|
||||||
expect(rootLink.overrides.name).toBe('Root component override');
|
expect(rootLink.overrides.name).toBe('Root component override');
|
||||||
@@ -193,9 +188,7 @@ describe('MachinesService', () => {
|
|||||||
const root = result?.componentLinks[0];
|
const root = result?.componentLinks[0];
|
||||||
expect(root?.childLinks[0].parent?.id).toBe('component-root');
|
expect(root?.childLinks[0].parent?.id).toBe('component-root');
|
||||||
expect(root?.childLinks[0].parent?.composantId).toBe('component-root');
|
expect(root?.childLinks[0].parent?.composantId).toBe('component-root');
|
||||||
expect(root?.childLinks[0].originalComposant.name).toBe(
|
expect(root?.childLinks[0].originalComposant.name).toBe('Child component');
|
||||||
'Child component',
|
|
||||||
);
|
|
||||||
expect(root?.childLinks[0].composant.name).toBe('Child component');
|
expect(root?.childLinks[0].composant.name).toBe('Child component');
|
||||||
expect(root?.pieceLinks[0].parent?.id).toBe('component-root');
|
expect(root?.pieceLinks[0].parent?.id).toBe('component-root');
|
||||||
expect(root?.pieceLinks[0].parent?.composantId).toBe('component-root');
|
expect(root?.pieceLinks[0].parent?.composantId).toBe('component-root');
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const MACHINE_PIECE_LINK_INCLUDE: Prisma.MachinePieceLinkInclude = {
|
|||||||
customField: { select: CUSTOM_FIELD_SELECT },
|
customField: { select: CUSTOM_FIELD_SELECT },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
typePiece: {
|
typePiece: {
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -75,7 +75,7 @@ const buildComponentLinkInclude = (
|
|||||||
const include: Prisma.MachineComponentLinkInclude = {
|
const include: Prisma.MachineComponentLinkInclude = {
|
||||||
composant: {
|
composant: {
|
||||||
include: {
|
include: {
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
typeComposant: {
|
typeComposant: {
|
||||||
include: {
|
include: {
|
||||||
customFields: true,
|
customFields: true,
|
||||||
@@ -119,7 +119,7 @@ const MACHINE_DEFAULT_INCLUDE = {
|
|||||||
typeMachine: {
|
typeMachine: {
|
||||||
include: TYPE_MACHINE_CONFIGURATION_INCLUDE,
|
include: TYPE_MACHINE_CONFIGURATION_INCLUDE,
|
||||||
},
|
},
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
componentLinks: {
|
componentLinks: {
|
||||||
include: MACHINE_COMPONENT_LINK_INCLUDE,
|
include: MACHINE_COMPONENT_LINK_INCLUDE,
|
||||||
},
|
},
|
||||||
@@ -200,7 +200,7 @@ type ComponentWithType = Prisma.ComposantGetPayload<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
type PieceWithType = Prisma.PieceGetPayload<{
|
type PieceWithType = Prisma.PieceGetPayload<{
|
||||||
include: { typePiece: true };
|
include: { typePiece: true; constructeurs: true };
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type CreatedComponentLinkInfo = {
|
type CreatedComponentLinkInfo = {
|
||||||
@@ -246,9 +246,7 @@ type PendingPieceLink = {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MachinesService {
|
export class MachinesService {
|
||||||
constructor(
|
constructor(private prisma: PrismaService) {}
|
||||||
private prisma: PrismaService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
private toLinkOverride(source: {
|
private toLinkOverride(source: {
|
||||||
nameOverride?: string | null;
|
nameOverride?: string | null;
|
||||||
@@ -273,7 +271,7 @@ export class MachinesService {
|
|||||||
const prix =
|
const prix =
|
||||||
overrides.prix !== null && overrides.prix !== undefined
|
overrides.prix !== null && overrides.prix !== undefined
|
||||||
? overrides.prix
|
? overrides.prix
|
||||||
: composant.prix ?? null;
|
: (composant.prix ?? null);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...composant,
|
...composant,
|
||||||
@@ -294,7 +292,7 @@ export class MachinesService {
|
|||||||
const prix =
|
const prix =
|
||||||
overrides.prix !== null && overrides.prix !== undefined
|
overrides.prix !== null && overrides.prix !== undefined
|
||||||
? overrides.prix
|
? overrides.prix
|
||||||
: piece.prix ?? null;
|
: (piece.prix ?? null);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...piece,
|
...piece,
|
||||||
@@ -346,7 +344,10 @@ export class MachinesService {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
const hydratedLink: HydratedComponentLink = {
|
const hydratedLink: HydratedComponentLink = {
|
||||||
...(rest as Omit<MachineComponentLinkWithRelations, 'pieceLinks' | 'composant'>),
|
...(rest as Omit<
|
||||||
|
MachineComponentLinkWithRelations,
|
||||||
|
'pieceLinks' | 'composant'
|
||||||
|
>),
|
||||||
parent: parentSummary,
|
parent: parentSummary,
|
||||||
overrides,
|
overrides,
|
||||||
originalComposant: composant,
|
originalComposant: composant,
|
||||||
@@ -375,26 +376,27 @@ export class MachinesService {
|
|||||||
sousComposants: [] as HierarchicalComponentLink[],
|
sousComposants: [] as HierarchicalComponentLink[],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const hierarchy = buildComponentHierarchy<HierarchicalComponentLink>(decorated);
|
const hierarchy =
|
||||||
|
buildComponentHierarchy<HierarchicalComponentLink>(decorated);
|
||||||
|
|
||||||
return hierarchy.map((link) => this.convertComponentLinkNode(link));
|
return hierarchy.map((link) => this.convertComponentLinkNode(link));
|
||||||
}
|
}
|
||||||
|
|
||||||
private hydrateMachine(
|
private hydrateMachine(machine: MachineWithRelations | null):
|
||||||
machine: MachineWithRelations | null,
|
| (MachineWithRelations & {
|
||||||
): (MachineWithRelations & {
|
componentLinks: HydratedComponentLink[];
|
||||||
componentLinks: HydratedComponentLink[];
|
pieceLinks: HydratedPieceLink[];
|
||||||
pieceLinks: HydratedPieceLink[];
|
})
|
||||||
}) | null {
|
| null {
|
||||||
if (!machine) {
|
if (!machine) {
|
||||||
return machine;
|
return machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentLinks = this.hydrateComponentLinks(
|
const componentLinks = this.hydrateComponentLinks(
|
||||||
(machine.componentLinks ?? []) as MachineComponentLinkWithRelations[],
|
machine.componentLinks ?? [],
|
||||||
);
|
);
|
||||||
|
|
||||||
const rootPieceLinks = ((machine.pieceLinks ?? []) as MachinePieceLinkWithRelations[])
|
const rootPieceLinks = (machine.pieceLinks ?? [])
|
||||||
.filter((link) => !link.parentLinkId)
|
.filter((link) => !link.parentLinkId)
|
||||||
.map((link) => this.hydratePieceLink(link));
|
.map((link) => this.hydratePieceLink(link));
|
||||||
|
|
||||||
@@ -533,7 +535,8 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const requirement of componentRequirements) {
|
for (const requirement of componentRequirements) {
|
||||||
const linksForRequirement = componentLinksByRequirement.get(requirement.id) ?? [];
|
const linksForRequirement =
|
||||||
|
componentLinksByRequirement.get(requirement.id) ?? [];
|
||||||
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
||||||
const max = requirement.maxCount ?? undefined;
|
const max = requirement.maxCount ?? undefined;
|
||||||
|
|
||||||
@@ -559,7 +562,8 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const requirement of pieceRequirements) {
|
for (const requirement of pieceRequirements) {
|
||||||
const linksForRequirement = pieceLinksByRequirement.get(requirement.id) ?? [];
|
const linksForRequirement =
|
||||||
|
pieceLinksByRequirement.get(requirement.id) ?? [];
|
||||||
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
||||||
const max = requirement.maxCount ?? undefined;
|
const max = requirement.maxCount ?? undefined;
|
||||||
|
|
||||||
@@ -646,6 +650,30 @@ export class MachinesService {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private normalizeConstructeurIds(ids?: string[] | null): string[] {
|
||||||
|
if (!Array.isArray(ids)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const cleaned = ids
|
||||||
|
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
||||||
|
.filter((item) => item.length > 0);
|
||||||
|
return Array.from(new Set(cleaned));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveExistingConstructeurIds(
|
||||||
|
ids: string[],
|
||||||
|
): Promise<string[]> {
|
||||||
|
if (!ids.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const existing = await this.prisma.constructeur.findMany({
|
||||||
|
where: { id: { in: ids } },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
const existingIds = new Set(existing.map(({ id }) => id));
|
||||||
|
return ids.filter((id) => existingIds.has(id));
|
||||||
|
}
|
||||||
|
|
||||||
private async resolveConstructeurId(
|
private async resolveConstructeurId(
|
||||||
input: unknown,
|
input: unknown,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
@@ -692,9 +720,12 @@ export class MachinesService {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveLinkIdentifier(link: { id?: string; linkId?: string }): string | undefined {
|
private resolveLinkIdentifier(link: {
|
||||||
|
id?: string;
|
||||||
|
linkId?: string;
|
||||||
|
}): string | undefined {
|
||||||
const candidate =
|
const candidate =
|
||||||
(typeof link.id === 'string' && link.id.trim())
|
typeof link.id === 'string' && link.id.trim()
|
||||||
? link.id.trim()
|
? link.id.trim()
|
||||||
: typeof link.linkId === 'string'
|
: typeof link.linkId === 'string'
|
||||||
? link.linkId.trim()
|
? link.linkId.trim()
|
||||||
@@ -703,9 +734,7 @@ export class MachinesService {
|
|||||||
return candidate && candidate.length > 0 ? candidate : undefined;
|
return candidate && candidate.length > 0 ? candidate : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildLinkOverrideMutation(
|
private buildLinkOverrideMutation(overrides?: Record<string, unknown>): {
|
||||||
overrides?: Record<string, unknown>,
|
|
||||||
): {
|
|
||||||
nameOverride?: string | null;
|
nameOverride?: string | null;
|
||||||
referenceOverride?: string | null;
|
referenceOverride?: string | null;
|
||||||
prixOverride?: Prisma.Decimal | null;
|
prixOverride?: Prisma.Decimal | null;
|
||||||
@@ -725,9 +754,7 @@ export class MachinesService {
|
|||||||
Object.prototype.hasOwnProperty.call(container, 'name') ||
|
Object.prototype.hasOwnProperty.call(container, 'name') ||
|
||||||
Object.prototype.hasOwnProperty.call(container, 'nom')
|
Object.prototype.hasOwnProperty.call(container, 'nom')
|
||||||
) {
|
) {
|
||||||
const value = this.extractString(
|
const value = this.extractString(container.name ?? container.nom);
|
||||||
container.name ?? container.nom,
|
|
||||||
);
|
|
||||||
mutation.nameOverride = value ?? null;
|
mutation.nameOverride = value ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +782,9 @@ export class MachinesService {
|
|||||||
container.priceOverride;
|
container.priceOverride;
|
||||||
const normalized = this.normalizePrice(rawPrice);
|
const normalized = this.normalizePrice(rawPrice);
|
||||||
if (normalized === undefined) {
|
if (normalized === undefined) {
|
||||||
throw new Error('La valeur de prix fournie dans les overrides est invalide.');
|
throw new Error(
|
||||||
|
'La valeur de prix fournie dans les overrides est invalide.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
mutation.prixOverride =
|
mutation.prixOverride =
|
||||||
normalized === null ? null : new Prisma.Decimal(normalized);
|
normalized === null ? null : new Prisma.Decimal(normalized);
|
||||||
@@ -800,7 +829,9 @@ export class MachinesService {
|
|||||||
return [...direct, ...legacy];
|
return [...direct, ...legacy];
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractStructurePieces(structure: Record<string, unknown> | null | undefined) {
|
private extractStructurePieces(
|
||||||
|
structure: Record<string, unknown> | null | undefined,
|
||||||
|
) {
|
||||||
if (!structure || typeof structure !== 'object') {
|
if (!structure || typeof structure !== 'object') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -815,7 +846,9 @@ export class MachinesService {
|
|||||||
return [...pieces, ...legacy];
|
return [...pieces, ...legacy];
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractStructureAlias(entry: Record<string, unknown> | null | undefined) {
|
private extractStructureAlias(
|
||||||
|
entry: Record<string, unknown> | null | undefined,
|
||||||
|
) {
|
||||||
if (!entry || typeof entry !== 'object') {
|
if (!entry || typeof entry !== 'object') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -848,7 +881,9 @@ export class MachinesService {
|
|||||||
return this.extractString(definition.reference) ?? null;
|
return this.extractString(definition.reference) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractStructurePieceName(entry: Record<string, unknown> | null | undefined) {
|
private extractStructurePieceName(
|
||||||
|
entry: Record<string, unknown> | null | undefined,
|
||||||
|
) {
|
||||||
if (!entry || typeof entry !== 'object') {
|
if (!entry || typeof entry !== 'object') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -959,7 +994,7 @@ export class MachinesService {
|
|||||||
where: { id: pieceId },
|
where: { id: pieceId },
|
||||||
include: {
|
include: {
|
||||||
typePiece: true,
|
typePiece: true,
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -994,9 +1029,7 @@ export class MachinesService {
|
|||||||
for (const rawPiece of structurePieces) {
|
for (const rawPiece of structurePieces) {
|
||||||
const pieceEntry = this.ensurePlainObject(rawPiece);
|
const pieceEntry = this.ensurePlainObject(rawPiece);
|
||||||
const selectedPieceId = this.extractString(
|
const selectedPieceId = this.extractString(
|
||||||
pieceEntry.selectedPieceId ??
|
pieceEntry.selectedPieceId ?? pieceEntry.pieceId ?? pieceEntry.id,
|
||||||
pieceEntry.pieceId ??
|
|
||||||
pieceEntry.id,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!selectedPieceId) {
|
if (!selectedPieceId) {
|
||||||
@@ -1045,7 +1078,8 @@ export class MachinesService {
|
|||||||
data: {
|
data: {
|
||||||
parentLinkId: linkInfo.id,
|
parentLinkId: linkInfo.id,
|
||||||
nameOverride:
|
nameOverride:
|
||||||
pieceNameOverride !== null && pieceNameOverride !== undefined
|
pieceNameOverride !== null &&
|
||||||
|
pieceNameOverride !== undefined
|
||||||
? pieceNameOverride
|
? pieceNameOverride
|
||||||
: existingPieceLink.nameOverride,
|
: existingPieceLink.nameOverride,
|
||||||
referenceOverride:
|
referenceOverride:
|
||||||
@@ -1069,7 +1103,8 @@ export class MachinesService {
|
|||||||
where: { id: existingPieceLink.id },
|
where: { id: existingPieceLink.id },
|
||||||
data: {
|
data: {
|
||||||
nameOverride:
|
nameOverride:
|
||||||
pieceNameOverride !== null && pieceNameOverride !== undefined
|
pieceNameOverride !== null &&
|
||||||
|
pieceNameOverride !== undefined
|
||||||
? pieceNameOverride
|
? pieceNameOverride
|
||||||
: existingPieceLink.nameOverride,
|
: existingPieceLink.nameOverride,
|
||||||
referenceOverride:
|
referenceOverride:
|
||||||
@@ -1116,9 +1151,7 @@ export class MachinesService {
|
|||||||
for (const rawEntry of subcomponents) {
|
for (const rawEntry of subcomponents) {
|
||||||
const entry = this.ensurePlainObject(rawEntry);
|
const entry = this.ensurePlainObject(rawEntry);
|
||||||
const selectedComponentId = this.extractString(
|
const selectedComponentId = this.extractString(
|
||||||
entry.selectedComponentId ??
|
entry.selectedComponentId ?? entry.componentId ?? entry.composantId,
|
||||||
entry.componentId ??
|
|
||||||
entry.composantId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!selectedComponentId) {
|
if (!selectedComponentId) {
|
||||||
@@ -1299,7 +1332,8 @@ export class MachinesService {
|
|||||||
createData.nameOverride = entry.overrideMutation.nameOverride;
|
createData.nameOverride = entry.overrideMutation.nameOverride;
|
||||||
}
|
}
|
||||||
if (entry.overrideMutation?.referenceOverride !== undefined) {
|
if (entry.overrideMutation?.referenceOverride !== undefined) {
|
||||||
createData.referenceOverride = entry.overrideMutation.referenceOverride;
|
createData.referenceOverride =
|
||||||
|
entry.overrideMutation.referenceOverride;
|
||||||
}
|
}
|
||||||
if (entry.overrideMutation?.prixOverride !== undefined) {
|
if (entry.overrideMutation?.prixOverride !== undefined) {
|
||||||
createData.prixOverride = entry.overrideMutation.prixOverride;
|
createData.prixOverride = entry.overrideMutation.prixOverride;
|
||||||
@@ -1469,7 +1503,7 @@ export class MachinesService {
|
|||||||
|
|
||||||
const pieces = await prisma.piece.findMany({
|
const pieces = await prisma.piece.findMany({
|
||||||
where: { id: { in: Array.from(pieceIds) } },
|
where: { id: { in: Array.from(pieceIds) } },
|
||||||
include: { typePiece: true },
|
include: { typePiece: true, constructeurs: true },
|
||||||
});
|
});
|
||||||
const pieceMap = new Map<string, PieceWithType>(
|
const pieceMap = new Map<string, PieceWithType>(
|
||||||
pieces.map((piece) => [piece.id, piece]),
|
pieces.map((piece) => [piece.id, piece]),
|
||||||
@@ -1567,7 +1601,8 @@ export class MachinesService {
|
|||||||
|
|
||||||
if (parentComponentRequirementId) {
|
if (parentComponentRequirementId) {
|
||||||
const matches =
|
const matches =
|
||||||
componentLinkIndex.byRequirementId.get(parentComponentRequirementId) ?? [];
|
componentLinkIndex.byRequirementId.get(parentComponentRequirementId) ??
|
||||||
|
[];
|
||||||
if (matches.length === 1) {
|
if (matches.length === 1) {
|
||||||
return matches[0].id;
|
return matches[0].id;
|
||||||
}
|
}
|
||||||
@@ -1658,6 +1693,7 @@ export class MachinesService {
|
|||||||
const {
|
const {
|
||||||
componentLinks = [],
|
componentLinks = [],
|
||||||
pieceLinks = [],
|
pieceLinks = [],
|
||||||
|
constructeurIds,
|
||||||
...machineData
|
...machineData
|
||||||
} = createMachineDto;
|
} = createMachineDto;
|
||||||
|
|
||||||
@@ -1667,27 +1703,38 @@ export class MachinesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedConstructeurIds =
|
||||||
|
this.normalizeConstructeurIds(constructeurIds);
|
||||||
|
|
||||||
|
const resolvedConstructeurIds = await this.resolveExistingConstructeurIds(
|
||||||
|
normalizedConstructeurIds,
|
||||||
|
);
|
||||||
|
|
||||||
const typeMachine = await this.getTypeMachineConfiguration(
|
const typeMachine = await this.getTypeMachineConfiguration(
|
||||||
machineData.typeMachineId,
|
machineData.typeMachineId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const { componentRequirementMap, pieceRequirementMap } =
|
||||||
componentRequirementMap,
|
this.buildConfigurationContext(typeMachine, componentLinks, pieceLinks);
|
||||||
pieceRequirementMap,
|
|
||||||
} = this.buildConfigurationContext(
|
|
||||||
typeMachine,
|
|
||||||
componentLinks,
|
|
||||||
pieceLinks,
|
|
||||||
);
|
|
||||||
|
|
||||||
let machine: Awaited<ReturnType<typeof this.prisma.machine.create>>;
|
let machine: Awaited<ReturnType<typeof this.prisma.machine.create>>;
|
||||||
try {
|
try {
|
||||||
|
const createData: any = {
|
||||||
|
...machineData,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (resolvedConstructeurIds.length) {
|
||||||
|
createData.constructeurs = {
|
||||||
|
connect: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
machine = await this.prisma.machine.create({
|
machine = await this.prisma.machine.create({
|
||||||
data: machineData,
|
data: createData,
|
||||||
include: {
|
include: {
|
||||||
site: true,
|
site: true,
|
||||||
typeMachine: true,
|
typeMachine: true,
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1776,11 +1823,7 @@ export class MachinesService {
|
|||||||
const typeMachine = machine.typeMachine as TypeMachineConfiguration;
|
const typeMachine = machine.typeMachine as TypeMachineConfiguration;
|
||||||
|
|
||||||
const { componentRequirementMap, pieceRequirementMap } =
|
const { componentRequirementMap, pieceRequirementMap } =
|
||||||
this.buildConfigurationContext(
|
this.buildConfigurationContext(typeMachine, componentLinks, pieceLinks);
|
||||||
typeMachine,
|
|
||||||
componentLinks,
|
|
||||||
pieceLinks,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.prisma.$transaction(async (tx) => {
|
await this.prisma.$transaction(async (tx) => {
|
||||||
await tx.machinePieceLink.deleteMany({ where: { machineId: id } });
|
await tx.machinePieceLink.deleteMany({ where: { machineId: id } });
|
||||||
@@ -1811,7 +1854,7 @@ export class MachinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, updateMachineDto: UpdateMachineDto) {
|
async update(id: string, updateMachineDto: UpdateMachineDto) {
|
||||||
const { name, reference, constructeurId, prix, typeMachineId } =
|
const { name, reference, constructeurIds, prix, typeMachineId } =
|
||||||
updateMachineDto;
|
updateMachineDto;
|
||||||
|
|
||||||
const data: Prisma.MachineUpdateInput = {};
|
const data: Prisma.MachineUpdateInput = {};
|
||||||
@@ -1824,11 +1867,15 @@ export class MachinesService {
|
|||||||
data.reference = reference;
|
data.reference = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constructeurId !== undefined) {
|
if (constructeurIds !== undefined) {
|
||||||
const resolvedConstructeurId = this.extractString(constructeurId);
|
const normalizedConstructeurIds =
|
||||||
data.constructeur = resolvedConstructeurId
|
this.normalizeConstructeurIds(constructeurIds);
|
||||||
? { connect: { id: resolvedConstructeurId } }
|
const resolvedConstructeurIds = await this.resolveExistingConstructeurIds(
|
||||||
: { disconnect: true };
|
normalizedConstructeurIds,
|
||||||
|
);
|
||||||
|
data.constructeurs = {
|
||||||
|
set: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prix !== undefined) {
|
if (prix !== undefined) {
|
||||||
@@ -1836,7 +1883,8 @@ export class MachinesService {
|
|||||||
if (normalizedPrice === undefined) {
|
if (normalizedPrice === undefined) {
|
||||||
throw new Error('Le prix fourni est invalide.');
|
throw new Error('Le prix fourni est invalide.');
|
||||||
}
|
}
|
||||||
data.prix = normalizedPrice === null ? null : new Prisma.Decimal(normalizedPrice);
|
data.prix =
|
||||||
|
normalizedPrice === null ? null : new Prisma.Decimal(normalizedPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeMachineId !== undefined) {
|
if (typeMachineId !== undefined) {
|
||||||
|
|||||||
@@ -218,9 +218,7 @@ export class ModelTypeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isUniqueNameConstraint(error)) {
|
if (this.isUniqueNameConstraint(error)) {
|
||||||
throw new ConflictException(
|
throw new ConflictException('Une catégorie avec ce nom existe déjà.');
|
||||||
'Une catégorie avec ce nom existe déjà.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,7 @@ describe('PiecesService', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [PiecesService, { provide: PrismaService, useValue: prisma }],
|
||||||
PiecesService,
|
|
||||||
{ provide: PrismaService, useValue: prisma },
|
|
||||||
],
|
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<PiecesService>(PiecesService);
|
service = module.get<PiecesService>(PiecesService);
|
||||||
@@ -43,7 +40,10 @@ describe('PiecesService', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
prisma.piece.create.mockResolvedValue({ id: 'piece-1', name: dto.name });
|
prisma.piece.create.mockResolvedValue({ id: 'piece-1', name: dto.name });
|
||||||
prisma.piece.findUnique.mockResolvedValue({ id: 'piece-1', name: dto.name });
|
prisma.piece.findUnique.mockResolvedValue({
|
||||||
|
id: 'piece-1',
|
||||||
|
name: dto.name,
|
||||||
|
});
|
||||||
prisma.customField.findMany.mockResolvedValue([]);
|
prisma.customField.findMany.mockResolvedValue([]);
|
||||||
prisma.customFieldValue.findMany.mockResolvedValue([]);
|
prisma.customFieldValue.findMany.mockResolvedValue([]);
|
||||||
|
|
||||||
@@ -56,8 +56,14 @@ describe('PiecesService', () => {
|
|||||||
it('updates a piece', async () => {
|
it('updates a piece', async () => {
|
||||||
const dto: UpdatePieceDto = { name: 'Updated piece' };
|
const dto: UpdatePieceDto = { name: 'Updated piece' };
|
||||||
|
|
||||||
prisma.piece.update.mockResolvedValue({ id: 'piece-1', name: 'Updated piece' });
|
prisma.piece.update.mockResolvedValue({
|
||||||
prisma.piece.findUnique.mockResolvedValue({ id: 'piece-1', name: 'Updated piece' });
|
id: 'piece-1',
|
||||||
|
name: 'Updated piece',
|
||||||
|
});
|
||||||
|
prisma.piece.findUnique.mockResolvedValue({
|
||||||
|
id: 'piece-1',
|
||||||
|
name: 'Updated piece',
|
||||||
|
});
|
||||||
prisma.customField.findMany.mockResolvedValue([]);
|
prisma.customField.findMany.mockResolvedValue([]);
|
||||||
prisma.customFieldValue.findMany.mockResolvedValue([]);
|
prisma.customFieldValue.findMany.mockResolvedValue([]);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const PIECE_WITH_RELATIONS_INCLUDE = {
|
|||||||
pieceCustomFields: true,
|
pieceCustomFields: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
constructeur: true,
|
constructeurs: true,
|
||||||
documents: true,
|
documents: true,
|
||||||
customFieldValues: {
|
customFieldValues: {
|
||||||
include: {
|
include: {
|
||||||
@@ -31,16 +31,23 @@ const PIECE_WITH_RELATIONS_INCLUDE = {
|
|||||||
export class PiecesService {
|
export class PiecesService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
private buildCreateInput(createPieceDto: CreatePieceDto): Prisma.PieceCreateInput {
|
private async buildCreateInput(
|
||||||
|
createPieceDto: CreatePieceDto,
|
||||||
|
): Promise<Prisma.PieceCreateInput> {
|
||||||
const data: Prisma.PieceCreateInput = {
|
const data: Prisma.PieceCreateInput = {
|
||||||
name: createPieceDto.name,
|
name: createPieceDto.name,
|
||||||
reference: createPieceDto.reference ?? null,
|
reference: createPieceDto.reference ?? null,
|
||||||
prix: createPieceDto.prix !== undefined ? createPieceDto.prix : null,
|
prix: createPieceDto.prix !== undefined ? createPieceDto.prix : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (createPieceDto.constructeurId) {
|
const constructeurIds = this.normalizeConstructeurIds(
|
||||||
data.constructeur = {
|
createPieceDto.constructeurIds,
|
||||||
connect: { id: createPieceDto.constructeurId },
|
);
|
||||||
|
const resolvedConstructeurIds =
|
||||||
|
await this.resolveExistingConstructeurIds(constructeurIds);
|
||||||
|
if (resolvedConstructeurIds.length) {
|
||||||
|
data.constructeurs = {
|
||||||
|
connect: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ export class PiecesService {
|
|||||||
async create(createPieceDto: CreatePieceDto) {
|
async create(createPieceDto: CreatePieceDto) {
|
||||||
try {
|
try {
|
||||||
const created = await this.prisma.piece.create({
|
const created = await this.prisma.piece.create({
|
||||||
data: this.buildCreateInput(createPieceDto),
|
data: await this.buildCreateInput(createPieceDto),
|
||||||
include: PIECE_WITH_RELATIONS_INCLUDE,
|
include: PIECE_WITH_RELATIONS_INCLUDE,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -103,10 +110,15 @@ export class PiecesService {
|
|||||||
data.prix = updatePieceDto.prix;
|
data.prix = updatePieceDto.prix;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatePieceDto.constructeurId !== undefined) {
|
if (updatePieceDto.constructeurIds !== undefined) {
|
||||||
data.constructeur = updatePieceDto.constructeurId
|
const constructeurIds = this.normalizeConstructeurIds(
|
||||||
? { connect: { id: updatePieceDto.constructeurId } }
|
updatePieceDto.constructeurIds,
|
||||||
: { disconnect: true };
|
);
|
||||||
|
const resolvedConstructeurIds =
|
||||||
|
await this.resolveExistingConstructeurIds(constructeurIds);
|
||||||
|
data.constructeurs = {
|
||||||
|
set: resolvedConstructeurIds.map((id) => ({ id })),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatePieceDto.typePieceId !== undefined) {
|
if (updatePieceDto.typePieceId !== undefined) {
|
||||||
@@ -224,6 +236,30 @@ export class PiecesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private normalizeConstructeurIds(ids?: string[] | null): string[] {
|
||||||
|
if (!Array.isArray(ids)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const cleaned = ids
|
||||||
|
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
||||||
|
.filter((item) => item.length > 0);
|
||||||
|
return Array.from(new Set(cleaned));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveExistingConstructeurIds(
|
||||||
|
ids: string[],
|
||||||
|
): Promise<string[]> {
|
||||||
|
if (!ids.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const existing = await this.prisma.constructeur.findMany({
|
||||||
|
where: { id: { in: ids } },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
const existingIds = new Set(existing.map(({ id }) => id));
|
||||||
|
return ids.filter((id) => existingIds.has(id));
|
||||||
|
}
|
||||||
|
|
||||||
private parsePieceSkeleton(value: unknown): PieceModelStructure | null {
|
private parsePieceSkeleton(value: unknown): PieceModelStructure | null {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return null;
|
return null;
|
||||||
@@ -430,4 +466,6 @@ type PieceTypeWithSkeleton = Prisma.ModelTypeGetPayload<{
|
|||||||
include: { pieceCustomFields: true };
|
include: { pieceCustomFields: true };
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type PieceCustomFieldEntry = NonNullable<PieceModelStructure['customFields']>[number];
|
type PieceCustomFieldEntry = NonNullable<
|
||||||
|
PieceModelStructure['customFields']
|
||||||
|
>[number];
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import { IsString, IsOptional, IsNumber, IsObject } from 'class-validator';
|
import {
|
||||||
|
IsString,
|
||||||
|
IsOptional,
|
||||||
|
IsNumber,
|
||||||
|
IsObject,
|
||||||
|
IsArray,
|
||||||
|
} from 'class-validator';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
|
|
||||||
export class CreateComposantDto {
|
export class CreateComposantDto {
|
||||||
@@ -18,8 +24,10 @@ export class CreateComposantDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsOptional()
|
||||||
constructeurId?: string;
|
@IsArray()
|
||||||
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => (value === '' ? null : value))
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@@ -49,8 +57,9 @@ export class UpdateComposantDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsArray()
|
||||||
constructeurId?: string;
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => (value === '' ? null : value))
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
|
|||||||
@@ -154,8 +154,9 @@ export class CreateMachineDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsArray()
|
||||||
constructeurId?: string;
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsDecimal()
|
@IsDecimal()
|
||||||
@@ -188,8 +189,9 @@ export class UpdateMachineDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsArray()
|
||||||
constructeurId?: string;
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsDecimal()
|
@IsDecimal()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IsString, IsOptional, IsNumber } from 'class-validator';
|
import { IsString, IsOptional, IsNumber, IsArray } from 'class-validator';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
|
|
||||||
export class CreatePieceDto {
|
export class CreatePieceDto {
|
||||||
@@ -18,8 +18,10 @@ export class CreatePieceDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsOptional()
|
||||||
constructeurId?: string;
|
@IsArray()
|
||||||
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => (value === '' ? null : value))
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
@@ -45,8 +47,10 @@ export class UpdatePieceDto {
|
|||||||
reference?: string;
|
reference?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsOptional()
|
||||||
constructeurId?: string;
|
@IsArray()
|
||||||
|
@IsString({ each: true })
|
||||||
|
constructeurIds?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Transform(({ value }) => (value === '' ? null : value))
|
@Transform(({ value }) => (value === '' ? null : value))
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ type MachineRecord = {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
reference: Nullable<string>;
|
reference: Nullable<string>;
|
||||||
constructeurId: Nullable<string>;
|
constructeurIds: string[];
|
||||||
prix: Nullable<string>;
|
prix: Nullable<string>;
|
||||||
siteId: string;
|
siteId: string;
|
||||||
typeMachineId: Nullable<string>;
|
typeMachineId: Nullable<string>;
|
||||||
@@ -90,7 +90,7 @@ type ComposantRecord = {
|
|||||||
parentComposantId: Nullable<string>;
|
parentComposantId: Nullable<string>;
|
||||||
typeComposantId: Nullable<string>;
|
typeComposantId: Nullable<string>;
|
||||||
typeMachineComponentRequirementId: Nullable<string>;
|
typeMachineComponentRequirementId: Nullable<string>;
|
||||||
constructeurId: Nullable<string>;
|
constructeurIds: string[];
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
};
|
};
|
||||||
@@ -104,7 +104,7 @@ type PieceRecord = {
|
|||||||
composantId: Nullable<string>;
|
composantId: Nullable<string>;
|
||||||
typePieceId: Nullable<string>;
|
typePieceId: Nullable<string>;
|
||||||
typeMachinePieceRequirementId: Nullable<string>;
|
typeMachinePieceRequirementId: Nullable<string>;
|
||||||
constructeurId: Nullable<string>;
|
constructeurIds: string[];
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
};
|
};
|
||||||
@@ -638,11 +638,12 @@ class InMemoryPrismaService {
|
|||||||
machine = {
|
machine = {
|
||||||
create: async ({ data, include }: any) => {
|
create: async ({ data, include }: any) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
const constructeurIds = this.extractConstructeurIds(data.constructeurs);
|
||||||
const record: MachineRecord = {
|
const record: MachineRecord = {
|
||||||
id: generateId('machine'),
|
id: generateId('machine'),
|
||||||
name: data.name,
|
name: data.name,
|
||||||
reference: data.reference ?? null,
|
reference: data.reference ?? null,
|
||||||
constructeurId: data.constructeurId ?? null,
|
constructeurIds,
|
||||||
prix: data.prix ?? null,
|
prix: data.prix ?? null,
|
||||||
siteId: data.siteId,
|
siteId: data.siteId,
|
||||||
typeMachineId: data.typeMachineId ?? null,
|
typeMachineId: data.typeMachineId ?? null,
|
||||||
@@ -683,6 +684,7 @@ class InMemoryPrismaService {
|
|||||||
composant = {
|
composant = {
|
||||||
create: async ({ data }: any) => {
|
create: async ({ data }: any) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
const constructeurIds = this.extractConstructeurIds(data.constructeurs);
|
||||||
const record: ComposantRecord = {
|
const record: ComposantRecord = {
|
||||||
id: generateId('component'),
|
id: generateId('component'),
|
||||||
name: data.name,
|
name: data.name,
|
||||||
@@ -693,7 +695,7 @@ class InMemoryPrismaService {
|
|||||||
typeComposantId: data.typeComposantId ?? null,
|
typeComposantId: data.typeComposantId ?? null,
|
||||||
typeMachineComponentRequirementId:
|
typeMachineComponentRequirementId:
|
||||||
data.typeMachineComponentRequirementId ?? null,
|
data.typeMachineComponentRequirementId ?? null,
|
||||||
constructeurId: data.constructeurId ?? null,
|
constructeurIds,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
@@ -719,6 +721,7 @@ class InMemoryPrismaService {
|
|||||||
piece = {
|
piece = {
|
||||||
create: async ({ data }: any) => {
|
create: async ({ data }: any) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
const constructeurIds = this.extractConstructeurIds(data.constructeurs);
|
||||||
const record: PieceRecord = {
|
const record: PieceRecord = {
|
||||||
id: generateId('piece'),
|
id: generateId('piece'),
|
||||||
name: data.name,
|
name: data.name,
|
||||||
@@ -729,7 +732,7 @@ class InMemoryPrismaService {
|
|||||||
typePieceId: data.typePieceId ?? null,
|
typePieceId: data.typePieceId ?? null,
|
||||||
typeMachinePieceRequirementId:
|
typeMachinePieceRequirementId:
|
||||||
data.typeMachinePieceRequirementId ?? null,
|
data.typeMachinePieceRequirementId ?? null,
|
||||||
constructeurId: data.constructeurId ?? null,
|
constructeurIds,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
@@ -767,7 +770,7 @@ class InMemoryPrismaService {
|
|||||||
prixOverride:
|
prixOverride:
|
||||||
data.prixOverride !== undefined && data.prixOverride !== null
|
data.prixOverride !== undefined && data.prixOverride !== null
|
||||||
? String(data.prixOverride)
|
? String(data.prixOverride)
|
||||||
: data.prixOverride ?? null,
|
: (data.prixOverride ?? null),
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
@@ -819,7 +822,7 @@ class InMemoryPrismaService {
|
|||||||
prixOverride:
|
prixOverride:
|
||||||
data.prixOverride !== undefined && data.prixOverride !== null
|
data.prixOverride !== undefined && data.prixOverride !== null
|
||||||
? String(data.prixOverride)
|
? String(data.prixOverride)
|
||||||
: data.prixOverride ?? null,
|
: (data.prixOverride ?? null),
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
@@ -848,7 +851,9 @@ class InMemoryPrismaService {
|
|||||||
(link) => link.parentLinkId === where.parentLinkId,
|
(link) => link.parentLinkId === where.parentLinkId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return links.map((link) => this.buildMachinePieceLink(link, include ?? {}));
|
return links.map((link) =>
|
||||||
|
this.buildMachinePieceLink(link, include ?? {}),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1279,6 +1284,37 @@ class InMemoryPrismaService {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extractConstructeurIds(input: any): string[] {
|
||||||
|
if (!input) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = Array.isArray(input.set)
|
||||||
|
? input.set
|
||||||
|
: Array.isArray(input.connect)
|
||||||
|
? input.connect
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return source
|
||||||
|
.map((entry: any) => (typeof entry?.id === 'string' ? entry.id : null))
|
||||||
|
.filter((id: string | null): id is string => Boolean(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapConstructeurs(ids: string[] = []) {
|
||||||
|
if (!Array.isArray(ids) || ids.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
.map((id) =>
|
||||||
|
this.constructeurs.find((constructeur) => constructeur.id === id),
|
||||||
|
)
|
||||||
|
.filter((item): item is (typeof this.constructeurs)[number] =>
|
||||||
|
Boolean(item),
|
||||||
|
)
|
||||||
|
.map((item) => ({ ...item }));
|
||||||
|
}
|
||||||
|
|
||||||
private buildMachine(machine: MachineRecord, include: any) {
|
private buildMachine(machine: MachineRecord, include: any) {
|
||||||
const base: any = { ...machine };
|
const base: any = { ...machine };
|
||||||
|
|
||||||
@@ -1309,8 +1345,8 @@ class InMemoryPrismaService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.constructeur) {
|
if (include?.constructeurs) {
|
||||||
base.constructeur = null;
|
base.constructeurs = this.mapConstructeurs(machine.constructeurIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.componentLinks) {
|
if (include?.componentLinks) {
|
||||||
@@ -1389,19 +1425,19 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typeMachineComponentRequirement) {
|
if (include?.typeMachineComponentRequirement) {
|
||||||
const requirement = link.typeMachineComponentRequirementId
|
const requirement = link.typeMachineComponentRequirementId
|
||||||
? this.typeMachineComponentRequirements.find(
|
? (this.typeMachineComponentRequirements.find(
|
||||||
(item) => item.id === link.typeMachineComponentRequirementId,
|
(item) => item.id === link.typeMachineComponentRequirementId,
|
||||||
) ?? null
|
) ?? null)
|
||||||
: null;
|
: null;
|
||||||
base.typeMachineComponentRequirement = requirement
|
base.typeMachineComponentRequirement = requirement
|
||||||
? {
|
? {
|
||||||
...requirement,
|
...requirement,
|
||||||
typeComposant:
|
typeComposant: include.typeMachineComponentRequirement.include
|
||||||
include.typeMachineComponentRequirement.include?.typeComposant
|
?.typeComposant
|
||||||
? this.typeComposants.find(
|
? (this.typeComposants.find(
|
||||||
(item) => item.id === requirement.typeComposantId,
|
(item) => item.id === requirement.typeComposantId,
|
||||||
) ?? null
|
) ?? null)
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
@@ -1419,14 +1455,12 @@ class InMemoryPrismaService {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildMachinePieceLink(
|
private buildMachinePieceLink(link: MachinePieceLinkRecord, include: any) {
|
||||||
link: MachinePieceLinkRecord,
|
|
||||||
include: any,
|
|
||||||
) {
|
|
||||||
const base: any = { ...link };
|
const base: any = { ...link };
|
||||||
|
|
||||||
if (include?.piece) {
|
if (include?.piece) {
|
||||||
const piece = this.pieces.find((item) => item.id === link.pieceId) ?? null;
|
const piece =
|
||||||
|
this.pieces.find((item) => item.id === link.pieceId) ?? null;
|
||||||
base.piece = piece
|
base.piece = piece
|
||||||
? this.buildPiece(piece, include.piece.include ?? {})
|
? this.buildPiece(piece, include.piece.include ?? {})
|
||||||
: null;
|
: null;
|
||||||
@@ -1434,19 +1468,18 @@ class InMemoryPrismaService {
|
|||||||
|
|
||||||
if (include?.typeMachinePieceRequirement) {
|
if (include?.typeMachinePieceRequirement) {
|
||||||
const requirement = link.typeMachinePieceRequirementId
|
const requirement = link.typeMachinePieceRequirementId
|
||||||
? this.typeMachinePieceRequirements.find(
|
? (this.typeMachinePieceRequirements.find(
|
||||||
(item) => item.id === link.typeMachinePieceRequirementId,
|
(item) => item.id === link.typeMachinePieceRequirementId,
|
||||||
) ?? null
|
) ?? null)
|
||||||
: null;
|
: null;
|
||||||
base.typeMachinePieceRequirement = requirement
|
base.typeMachinePieceRequirement = requirement
|
||||||
? {
|
? {
|
||||||
...requirement,
|
...requirement,
|
||||||
typePiece:
|
typePiece: include.typeMachinePieceRequirement.include?.typePiece
|
||||||
include.typeMachinePieceRequirement.include?.typePiece
|
? (this.typePieces.find(
|
||||||
? this.typePieces.find(
|
(item) => item.id === requirement.typePieceId,
|
||||||
(item) => item.id === requirement.typePieceId,
|
) ?? null)
|
||||||
) ?? null
|
: undefined,
|
||||||
: undefined,
|
|
||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
@@ -1505,8 +1538,8 @@ class InMemoryPrismaService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.constructeur) {
|
if (include?.constructeurs) {
|
||||||
base.constructeur = null;
|
base.constructeurs = this.mapConstructeurs(component.constructeurIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.pieces) {
|
if (include?.pieces) {
|
||||||
@@ -1536,8 +1569,8 @@ class InMemoryPrismaService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.constructeur) {
|
if (include?.constructeurs) {
|
||||||
base.constructeur = null;
|
base.constructeurs = this.mapConstructeurs(piece.constructeurIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (include?.typeMachinePieceRequirement) {
|
if (include?.typeMachinePieceRequirement) {
|
||||||
|
|||||||
Reference in New Issue
Block a user