feat: centralize constructeur link synchronization

This commit is contained in:
Matthieu
2025-10-30 11:32:34 +01:00
parent fe471b9e81
commit d05b91d7cd
6 changed files with 713 additions and 89 deletions

View File

@@ -1,6 +1,7 @@
import { ConflictException, Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import { syncConstructeurLinks } from '../common/utils/constructeur-link.util';
import { CreatePieceDto, UpdatePieceDto } from '../shared/dto/piece.dto';
import { PieceModelStructureSchema } from '../shared/schemas/inventory';
import type { PieceModelStructure } from '../shared/types/inventory';
@@ -35,7 +36,7 @@ export class PiecesService {
private async buildCreateInput(
createPieceDto: CreatePieceDto,
): Promise<Prisma.PieceCreateInput> {
): Promise<{ data: Prisma.PieceCreateInput; constructeurIds: string[] }> {
const data: Prisma.PieceCreateInput = {
name: createPieceDto.name,
reference: createPieceDto.reference ?? null,
@@ -47,11 +48,6 @@ export class PiecesService {
);
const resolvedConstructeurIds =
await this.resolveExistingConstructeurIds(constructeurIds);
if (resolvedConstructeurIds.length) {
data.constructeurs = {
connect: resolvedConstructeurIds.map((id) => ({ id })),
};
}
if (createPieceDto.typePieceId) {
data.typePiece = {
@@ -59,25 +55,46 @@ export class PiecesService {
};
}
return data;
return { data, constructeurIds: resolvedConstructeurIds };
}
async create(createPieceDto: CreatePieceDto) {
try {
const { data, constructeurIds } = await this.buildCreateInput(
createPieceDto,
);
const created = await this.prisma.piece.create({
data: await this.buildCreateInput(createPieceDto),
data,
include: PIECE_WITH_RELATIONS_INCLUDE,
});
let syncedConstructeurIds: string[] = [];
if (constructeurIds.length > 0) {
syncedConstructeurIds = await syncConstructeurLinks(
this.prisma,
'_PieceConstructeurs',
created.id,
constructeurIds,
);
}
await this.applyPieceSkeleton({
pieceId: created.id,
typePiece: created.typePiece as PieceTypeWithSkeleton | null,
prisma: this.prisma,
});
return this.prisma.piece.findUnique({
const refreshed = await this.prisma.piece.findUnique({
where: { id: created.id },
include: PIECE_WITH_RELATIONS_INCLUDE,
});
if (refreshed && syncedConstructeurIds.length > 0) {
(refreshed as typeof refreshed & { constructeurIds?: string[] }).constructeurIds =
[...syncedConstructeurIds];
}
return refreshed;
} catch (error) {
this.handlePrismaError(error);
}
@@ -112,15 +129,14 @@ export class PiecesService {
data.prix = updatePieceDto.prix;
}
let resolvedConstructeurIds: string[] | undefined;
if (updatePieceDto.constructeurIds !== undefined) {
const constructeurIds = this.normalizeConstructeurIds(
updatePieceDto.constructeurIds,
);
const resolvedConstructeurIds =
await this.resolveExistingConstructeurIds(constructeurIds);
data.constructeurs = {
set: resolvedConstructeurIds.map((id) => ({ id })),
};
resolvedConstructeurIds = await this.resolveExistingConstructeurIds(
constructeurIds,
);
}
if (updatePieceDto.typePieceId !== undefined) {
@@ -129,22 +145,42 @@ export class PiecesService {
: { disconnect: true };
}
let syncedConstructeurIds: string[] | undefined;
try {
const updated = await this.prisma.piece.update({
await this.prisma.$transaction(async (tx) => {
const updated = await tx.piece.update({
where: { id },
data,
include: PIECE_WITH_RELATIONS_INCLUDE,
});
if (resolvedConstructeurIds !== undefined) {
syncedConstructeurIds = await syncConstructeurLinks(
tx,
'_PieceConstructeurs',
id,
resolvedConstructeurIds,
);
}
await this.applyPieceSkeleton({
pieceId: updated.id,
typePiece: updated.typePiece as PieceTypeWithSkeleton | null,
prisma: tx,
});
});
const refreshed = await this.prisma.piece.findUnique({
where: { id },
data,
include: PIECE_WITH_RELATIONS_INCLUDE,
});
await this.applyPieceSkeleton({
pieceId: updated.id,
typePiece: updated.typePiece as PieceTypeWithSkeleton | null,
});
if (refreshed && syncedConstructeurIds) {
(refreshed as typeof refreshed & { constructeurIds?: string[] }).constructeurIds =
[...syncedConstructeurIds];
}
return this.prisma.piece.findUnique({
where: { id: updated.id },
include: PIECE_WITH_RELATIONS_INCLUDE,
});
return refreshed;
} catch (error) {
this.handlePrismaError(error);
}
@@ -211,9 +247,11 @@ export class PiecesService {
private async applyPieceSkeleton({
pieceId,
typePiece,
prisma,
}: {
pieceId: string;
typePiece: PieceTypeWithSkeleton | null;
prisma: Prisma.TransactionClient | PrismaService;
}) {
if (!typePiece?.id) {
return;
@@ -230,8 +268,13 @@ export class PiecesService {
const customFields = skeleton.customFields ?? [];
await this.ensurePieceCustomFieldDefinitions(typePiece.id, customFields);
await this.ensurePieceCustomFieldDefinitions(
prisma,
typePiece.id,
customFields,
);
await this.createPieceCustomFieldValues(
prisma,
pieceId,
typePiece.id,
customFields,
@@ -275,6 +318,7 @@ export class PiecesService {
}
private async ensurePieceCustomFieldDefinitions(
prisma: Prisma.TransactionClient | PrismaService,
typePieceId: string,
customFields: PieceModelStructure['customFields'],
) {
@@ -286,7 +330,7 @@ export class PiecesService {
return;
}
const existing = await this.prisma.customField.findMany({
const existing = await prisma.customField.findMany({
where: { typePieceId },
select: { id: true, name: true, orderIndex: true },
});
@@ -312,7 +356,7 @@ export class PiecesService {
const existingField = existingByName.get(name);
if (existingField) {
if (existingField.orderIndex !== index) {
await this.prisma.customField.update({
await prisma.customField.update({
where: { id: existingField.id },
data: { orderIndex: index },
});
@@ -324,7 +368,7 @@ export class PiecesService {
const required = Boolean(field.required);
const options = this.normalizeOptions(field);
const created = await this.prisma.customField.create({
const created = await prisma.customField.create({
data: {
name,
type,
@@ -341,6 +385,7 @@ export class PiecesService {
}
private async createPieceCustomFieldValues(
prisma: Prisma.TransactionClient | PrismaService,
pieceId: string,
typePieceId: string,
customFields: PieceModelStructure['customFields'],
@@ -353,7 +398,7 @@ export class PiecesService {
return;
}
const definitions = await this.prisma.customField.findMany({
const definitions = await prisma.customField.findMany({
where: { typePieceId },
select: { id: true, name: true },
});
@@ -369,7 +414,7 @@ export class PiecesService {
]),
);
const existingValues = await this.prisma.customFieldValue.findMany({
const existingValues = await prisma.customFieldValue.findMany({
where: { pieceId },
select: { customFieldId: true },
});
@@ -393,7 +438,7 @@ export class PiecesService {
continue;
}
await this.prisma.customFieldValue.create({
await prisma.customFieldValue.create({
data: {
customFieldId: definitionId,
pieceId,