feat: auto populate machine structures and seed sample data

This commit is contained in:
Matthieu
2025-10-13 09:01:33 +02:00
parent b7682ac312
commit dc4a12440b
21 changed files with 2218 additions and 7267 deletions

View File

@@ -109,6 +109,32 @@ type PieceRecord = {
updatedAt: Date;
};
type MachineComponentLinkRecord = {
id: string;
machineId: string;
composantId: string;
parentLinkId: Nullable<string>;
typeMachineComponentRequirementId: Nullable<string>;
nameOverride: Nullable<string>;
referenceOverride: Nullable<string>;
prixOverride: Nullable<string>;
createdAt: Date;
updatedAt: Date;
};
type MachinePieceLinkRecord = {
id: string;
machineId: string;
pieceId: string;
parentLinkId: Nullable<string>;
typeMachinePieceRequirementId: Nullable<string>;
nameOverride: Nullable<string>;
referenceOverride: Nullable<string>;
prixOverride: Nullable<string>;
createdAt: Date;
updatedAt: Date;
};
type ModelTypeRecord = {
id: string;
name: string;
@@ -171,6 +197,8 @@ class InMemoryPrismaService {
private machines: MachineRecord[] = [];
private composants: ComposantRecord[] = [];
private pieces: PieceRecord[] = [];
private machineComponentLinks: MachineComponentLinkRecord[] = [];
private machinePieceLinks: MachinePieceLinkRecord[] = [];
private customFields: CustomFieldRecord[] = [];
private customFieldValues: CustomFieldValueRecord[] = [];
private profiles: ProfileRecord[] = [];
@@ -196,6 +224,8 @@ class InMemoryPrismaService {
this.machines = [];
this.composants = [];
this.pieces = [];
this.machineComponentLinks = [];
this.machinePieceLinks = [];
this.customFields = [];
this.customFieldValues = [];
this.profiles = [];
@@ -720,6 +750,108 @@ class InMemoryPrismaService {
},
};
machineComponentLink = {
create: async ({ data, include }: any) => {
const now = new Date();
const record: MachineComponentLinkRecord = {
id: data.id ?? generateId('mcl'),
machineId: data.machineId,
composantId: data.composantId,
parentLinkId: data.parentLinkId ?? null,
typeMachineComponentRequirementId:
data.typeMachineComponentRequirementId ?? null,
nameOverride:
data.nameOverride !== undefined ? data.nameOverride : null,
referenceOverride:
data.referenceOverride !== undefined ? data.referenceOverride : null,
prixOverride:
data.prixOverride !== undefined && data.prixOverride !== null
? String(data.prixOverride)
: data.prixOverride ?? null,
createdAt: now,
updatedAt: now,
};
this.machineComponentLinks.push(record);
return this.buildMachineComponentLink(record, include ?? {});
},
deleteMany: async ({ where }: any) => {
const before = this.machineComponentLinks.length;
this.machineComponentLinks = this.machineComponentLinks.filter((link) => {
if (where?.machineId !== undefined) {
return link.machineId !== where.machineId;
}
return true;
});
return { count: before - this.machineComponentLinks.length };
},
findMany: async ({ where, include }: any = {}) => {
let links = this.machineComponentLinks;
if (where?.machineId) {
links = links.filter((link) => link.machineId === where.machineId);
}
if (where?.parentLinkId === null) {
links = links.filter((link) => link.parentLinkId === null);
} else if (where?.parentLinkId) {
links = links.filter(
(link) => link.parentLinkId === where.parentLinkId,
);
}
return links.map((link) =>
this.buildMachineComponentLink(link, include ?? {}),
);
},
};
machinePieceLink = {
create: async ({ data, include }: any) => {
const now = new Date();
const record: MachinePieceLinkRecord = {
id: data.id ?? generateId('mpl'),
machineId: data.machineId,
pieceId: data.pieceId,
parentLinkId: data.parentLinkId ?? null,
typeMachinePieceRequirementId:
data.typeMachinePieceRequirementId ?? null,
nameOverride:
data.nameOverride !== undefined ? data.nameOverride : null,
referenceOverride:
data.referenceOverride !== undefined ? data.referenceOverride : null,
prixOverride:
data.prixOverride !== undefined && data.prixOverride !== null
? String(data.prixOverride)
: data.prixOverride ?? null,
createdAt: now,
updatedAt: now,
};
this.machinePieceLinks.push(record);
return this.buildMachinePieceLink(record, include ?? {});
},
deleteMany: async ({ where }: any) => {
const before = this.machinePieceLinks.length;
this.machinePieceLinks = this.machinePieceLinks.filter((link) => {
if (where?.machineId !== undefined) {
return link.machineId !== where.machineId;
}
return true;
});
return { count: before - this.machinePieceLinks.length };
},
findMany: async ({ where, include }: any = {}) => {
let links = this.machinePieceLinks;
if (where?.machineId) {
links = links.filter((link) => link.machineId === where.machineId);
}
if (where?.parentLinkId === null) {
links = links.filter((link) => link.parentLinkId === null);
} else if (where?.parentLinkId) {
links = links.filter(
(link) => link.parentLinkId === where.parentLinkId,
);
}
return links.map((link) => this.buildMachinePieceLink(link, include ?? {}));
},
};
customField = {
create: async ({ data }: any) => {
const now = new Date();
@@ -1181,6 +1313,27 @@ class InMemoryPrismaService {
base.constructeur = null;
}
if (include?.componentLinks) {
const links = this.machineComponentLinks.filter(
(link) => link.machineId === machine.id,
);
base.componentLinks = links.map((link) =>
this.buildMachineComponentLink(
link,
include.componentLinks.include ?? {},
),
);
}
if (include?.pieceLinks) {
const links = this.machinePieceLinks.filter(
(link) => link.machineId === machine.id,
);
base.pieceLinks = links.map((link) =>
this.buildMachinePieceLink(link, include.pieceLinks.include ?? {}),
);
}
if (include?.composants) {
const composants = this.composants.filter(
(component) => component.machineId === machine.id,
@@ -1220,6 +1373,87 @@ class InMemoryPrismaService {
return base;
}
private buildMachineComponentLink(
link: MachineComponentLinkRecord,
include: any,
) {
const base: any = { ...link };
if (include?.composant) {
const composant =
this.composants.find((item) => item.id === link.composantId) ?? null;
base.composant = composant
? this.buildComponent(composant, include.composant.include ?? {})
: null;
}
if (include?.typeMachineComponentRequirement) {
const requirement = link.typeMachineComponentRequirementId
? this.typeMachineComponentRequirements.find(
(item) => item.id === link.typeMachineComponentRequirementId,
) ?? null
: null;
base.typeMachineComponentRequirement = requirement
? {
...requirement,
typeComposant:
include.typeMachineComponentRequirement.include?.typeComposant
? this.typeComposants.find(
(item) => item.id === requirement.typeComposantId,
) ?? null
: undefined,
}
: null;
}
if (include?.pieceLinks) {
const nestedInclude = include.pieceLinks.include ?? {};
const pieces = this.machinePieceLinks.filter(
(pieceLink) => pieceLink.parentLinkId === link.id,
);
base.pieceLinks = pieces.map((pieceLink) =>
this.buildMachinePieceLink(pieceLink, nestedInclude),
);
}
return base;
}
private buildMachinePieceLink(
link: MachinePieceLinkRecord,
include: any,
) {
const base: any = { ...link };
if (include?.piece) {
const piece = this.pieces.find((item) => item.id === link.pieceId) ?? null;
base.piece = piece
? this.buildPiece(piece, include.piece.include ?? {})
: null;
}
if (include?.typeMachinePieceRequirement) {
const requirement = link.typeMachinePieceRequirementId
? this.typeMachinePieceRequirements.find(
(item) => item.id === link.typeMachinePieceRequirementId,
) ?? null
: null;
base.typeMachinePieceRequirement = requirement
? {
...requirement,
typePiece:
include.typeMachinePieceRequirement.include?.typePiece
? this.typePieces.find(
(item) => item.id === requirement.typePieceId,
) ?? null
: undefined,
}
: null;
}
return base;
}
private buildComponent(component: ComposantRecord, include: any) {
const base: any = { ...component };
@@ -1459,42 +1693,46 @@ describe('Inventory flow (e2e)', () => {
const componentRequirementId = typeMachine.componentRequirements[0].id;
const pieceRequirementId = typeMachine.pieceRequirements[0].id;
const baseComponent = await prisma.composant.create({
data: {
name: 'Bloc moteur standard',
reference: 'COMP-BASE',
typeComposantId,
},
});
const basePiece = await prisma.piece.create({
data: {
name: 'Kit maintenance standard',
reference: 'KIT-BASE',
typePieceId,
},
});
const machineResponse = await request(app.getHttpServer())
.post('/machines')
.send({
name: 'Presse HP-2000',
siteId,
typeMachineId: typeMachine.id,
componentSelections: [
componentLinks: [
{
requirementId: componentRequirementId,
definition: {
composantId: baseComponent.id,
overrides: {
name: 'Bloc moteur série X',
reference: 'COMP-001',
customFields: [
{
name: 'Puissance nominale',
type: 'text',
required: true,
value: '7 kW',
},
],
prix: '12000.00',
},
},
],
pieceSelections: [
pieceLinks: [
{
requirementId: pieceRequirementId,
definition: {
pieceId: basePiece.id,
overrides: {
name: 'Kit maintenance niveau 1',
reference: 'KIT-001',
customFields: [
{
name: 'Référence fournisseur',
type: 'text',
value: 'STD-002',
},
],
},
},
],
@@ -1509,31 +1747,19 @@ describe('Inventory flow (e2e)', () => {
expect(machineDetailsResponse.status).toBe(200);
const machine = machineDetailsResponse.body;
expect(machine.composants).toHaveLength(1);
expect(machine.pieces).toHaveLength(1);
expect(machine.componentLinks).toHaveLength(1);
expect(machine.pieceLinks).toHaveLength(1);
const component = machine.composants[0];
expect(component.name).toBe('Bloc moteur série X');
expect(component.customFieldValues[0].value).toBe('7 kW');
const componentLink = machine.componentLinks[0];
expect(componentLink.composantId).toBe(baseComponent.id);
expect(componentLink.overrides.name).toBe('Bloc moteur série X');
expect(componentLink.composant.name).toBe('Bloc moteur série X');
expect(componentLink.originalComposant.name).toBe('Bloc moteur standard');
const piece = machine.pieces[0];
expect(piece.name).toBe('Kit maintenance niveau 1');
expect(piece.customFieldValues[0].value).toBe('STD-002');
const customFieldValueId = component.customFieldValues[0].id;
const updateResponse = await request(app.getHttpServer())
.patch(`/custom-fields/values/${customFieldValueId}`)
.send({ value: '8 kW' });
expect(updateResponse.status).toBe(200);
expect(updateResponse.body.value).toBe('8 kW');
const refreshedMachineResponse = await request(app.getHttpServer()).get(
`/machines/${machine.id}`,
);
expect(refreshedMachineResponse.status).toBe(200);
const refreshedComponent = refreshedMachineResponse.body.composants[0];
expect(refreshedComponent.customFieldValues[0].value).toBe('8 kW');
const pieceLink = machine.pieceLinks[0];
expect(pieceLink.pieceId).toBe(basePiece.id);
expect(pieceLink.overrides.name).toBe('Kit maintenance niveau 1');
expect(pieceLink.piece.name).toBe('Kit maintenance niveau 1');
});
describe('POST /composants', () => {