diff --git a/src/pieces/pieces.service.ts b/src/pieces/pieces.service.ts index ccd3466..61c035e 100644 --- a/src/pieces/pieces.service.ts +++ b/src/pieces/pieces.service.ts @@ -1,7 +1,10 @@ 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 { + fetchConstructeurIds, + 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'; @@ -120,30 +123,39 @@ export class PiecesService { include: PIECE_WITH_RELATIONS_INCLUDE, }); - if (refreshed && syncedConstructeurIds.length > 0) { - ( - refreshed as typeof refreshed & { constructeurIds?: string[] } - ).constructeurIds = [...syncedConstructeurIds]; + if (!refreshed) { + return null; } - return refreshed; + const mapped = await this.mapPiece(refreshed); + if (syncedConstructeurIds.length > 0) { + mapped.constructeurIds = [...syncedConstructeurIds]; + } + + return mapped; } catch (error) { this.handlePrismaError(error); } } async findAll() { - return this.prisma.piece.findMany({ + const items = await this.prisma.piece.findMany({ include: PIECE_WITH_RELATIONS_INCLUDE, orderBy: { name: 'asc' }, }); + const hydrated = await Promise.all(items.map((piece) => this.mapPiece(piece))); + return hydrated; } async findOne(id: string) { - return this.prisma.piece.findUnique({ + const piece = await this.prisma.piece.findUnique({ where: { id }, include: PIECE_WITH_RELATIONS_INCLUDE, }); + if (!piece) { + return null; + } + return this.mapPiece(piece); } async update(id: string, updatePieceDto: UpdatePieceDto) { @@ -217,13 +229,16 @@ export class PiecesService { include: PIECE_WITH_RELATIONS_INCLUDE, }); - if (refreshed && syncedConstructeurIds) { - ( - refreshed as typeof refreshed & { constructeurIds?: string[] } - ).constructeurIds = [...syncedConstructeurIds]; + if (!refreshed) { + return null; } - return refreshed; + const mapped = await this.mapPiece(refreshed); + if (syncedConstructeurIds) { + mapped.constructeurIds = [...syncedConstructeurIds]; + } + + return mapped; } catch (error) { this.handlePrismaError(error); } @@ -668,6 +683,43 @@ export class PiecesService { } return false; } + + private async mapPiece(piece: any) { + const idsFromConstructeurs = Array.isArray(piece.constructeurs) + ? piece.constructeurs + .map((c) => (c && typeof c.id === 'string' ? c.id : null)) + .filter((id): id is string => Boolean(id)) + : []; + + const idsFromPayload = Array.isArray(piece.constructeurIds) + ? piece.constructeurIds + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter((value) => value.length > 0) + : []; + + let ids = Array.from(new Set([...idsFromConstructeurs, ...idsFromPayload])); + + if (!ids.length) { + ids = await fetchConstructeurIds( + this.prisma, + '_PieceConstructeurs', + piece.id, + ); + } + + let constructeurs = piece.constructeurs; + if ((!constructeurs || !constructeurs.length) && ids.length) { + constructeurs = await this.prisma.constructeur.findMany({ + where: { id: { in: ids } }, + }); + } + + return { + ...piece, + constructeurs, + constructeurIds: ids, + }; + } } type PieceTypeWithSkeleton = Prisma.ModelTypeGetPayload<{ diff --git a/src/products/products.service.ts b/src/products/products.service.ts index ba58950..b16a8b2 100644 --- a/src/products/products.service.ts +++ b/src/products/products.service.ts @@ -301,9 +301,57 @@ export class ProductsService { } private mapProduct(product: ProductWithRelations) { + const constructeurs = Array.isArray(product.constructeurs) + ? product.constructeurs + .map((constructeur) => { + if (!constructeur || typeof constructeur !== 'object') { + return null; + } + const { id, name, email, phone, createdAt, updatedAt } = + constructeur as { + id?: string; + name?: string | null; + email?: string | null; + phone?: string | null; + createdAt?: Date; + updatedAt?: Date; + }; + + if (!id) { + return null; + } + return { + id, + name: name ?? null, + email: email ?? null, + phone: phone ?? null, + createdAt: createdAt ?? null, + updatedAt: updatedAt ?? null, + }; + }) + .filter( + (entry): entry is { + id: string; + name: string | null; + email: string | null; + phone: string | null; + createdAt: Date | null; + updatedAt: Date | null; + } => Boolean(entry), + ) + : []; + + const constructeurIds = constructeurs.map((item) => item.id); + const constructeursLabel = constructeurs + .map((item) => (item.name || '').trim()) + .filter((name) => name.length > 0) + .join(', '); + return { ...product, - constructeurIds: product.constructeurs.map((item) => item.id), + constructeurs, + constructeurIds, + constructeursLabel: constructeursLabel || null, }; }