feat: synchronize backend and frontend custom field handling
This commit is contained in:
@@ -2,6 +2,33 @@ import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { CreatePieceDto, UpdatePieceDto } from '../shared/dto/piece.dto';
|
||||
|
||||
const PIECE_WITH_RELATIONS_INCLUDE = {
|
||||
machine: true,
|
||||
composant: true,
|
||||
typePiece: {
|
||||
include: {
|
||||
customFields: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: {
|
||||
include: {
|
||||
customFields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export class PiecesService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
@@ -146,24 +173,7 @@ export class PiecesService {
|
||||
async findByMachine(machineId: string) {
|
||||
return this.prisma.piece.findMany({
|
||||
where: { machineId },
|
||||
include: {
|
||||
machine: true,
|
||||
composant: true,
|
||||
typePiece: true,
|
||||
documents: true,
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: PIECE_WITH_RELATIONS_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -199,39 +209,20 @@ export class PiecesService {
|
||||
async findByComposant(composantId: string) {
|
||||
return this.prisma.piece.findMany({
|
||||
where: { composantId },
|
||||
include: {
|
||||
machine: true,
|
||||
composant: true,
|
||||
typePiece: true,
|
||||
documents: true,
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: PIECE_WITH_RELATIONS_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, updatePieceDto: UpdatePieceDto) {
|
||||
return this.prisma.piece.update({
|
||||
const updated = await this.prisma.piece.update({
|
||||
where: { id },
|
||||
data: updatePieceDto,
|
||||
include: {
|
||||
machine: true,
|
||||
composant: true,
|
||||
typePiece: true,
|
||||
documents: true,
|
||||
constructeur: true,
|
||||
},
|
||||
include: PIECE_WITH_RELATIONS_INCLUDE,
|
||||
});
|
||||
|
||||
await this.syncPieceModelCustomFields(updated);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
async remove(id: string) {
|
||||
@@ -239,4 +230,137 @@ export class PiecesService {
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
private async syncPieceModelCustomFields(piece: any) {
|
||||
const pieceModelId = piece?.pieceModelId;
|
||||
|
||||
if (!pieceModelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = await this.prisma.pieceModel.findUnique({
|
||||
where: { id: pieceModelId },
|
||||
select: { structure: true },
|
||||
});
|
||||
|
||||
if (!model?.structure) {
|
||||
return;
|
||||
}
|
||||
|
||||
const structure = this.asRecord(model.structure);
|
||||
const customFields = this.extractCustomFields(structure);
|
||||
|
||||
const targetTypePieceId = this.getTypePieceIdForPiece(piece, structure);
|
||||
if (!targetTypePieceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.ensureCustomFieldsForType(
|
||||
targetTypePieceId,
|
||||
customFields,
|
||||
);
|
||||
}
|
||||
|
||||
private async ensureCustomFieldsForType(
|
||||
typePieceId: string,
|
||||
fields: any,
|
||||
) {
|
||||
if (!typePieceId || !Array.isArray(fields)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const field of fields) {
|
||||
if (!field || typeof field !== 'object') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name = typeof field.name === 'string' ? field.name.trim() : '';
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const type = typeof field.type === 'string' && field.type.trim()
|
||||
? field.type.trim()
|
||||
: 'text';
|
||||
const required = !!field.required;
|
||||
const options = this.normalizeOptions(field);
|
||||
|
||||
const existing = await this.prisma.customField.findFirst({
|
||||
where: {
|
||||
name,
|
||||
type,
|
||||
typePieceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
await this.prisma.customField.create({
|
||||
data: {
|
||||
name,
|
||||
type,
|
||||
required,
|
||||
options,
|
||||
typePieceId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private normalizeOptions(field: any): string[] | undefined {
|
||||
if (Array.isArray(field?.options)) {
|
||||
const normalized = field.options
|
||||
.map((option: any) =>
|
||||
typeof option === 'string' ? option.trim() : '',
|
||||
)
|
||||
.filter((option: string) => option.length > 0);
|
||||
|
||||
return normalized.length ? normalized : undefined;
|
||||
}
|
||||
|
||||
if (typeof field?.optionsText === 'string') {
|
||||
const normalized = field.optionsText
|
||||
.split(/\r?\n/)
|
||||
.map((option: string) => option.trim())
|
||||
.filter((option: string) => option.length > 0);
|
||||
|
||||
return normalized.length ? normalized : undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getTypePieceIdForPiece(
|
||||
piece: any,
|
||||
modelStructure: Record<string, any> | null,
|
||||
): string | null {
|
||||
const structure = this.asRecord(modelStructure);
|
||||
const structureTypePiece = this.asRecord(structure?.typePiece ?? null);
|
||||
|
||||
return (
|
||||
piece?.typePieceId ||
|
||||
piece?.typePiece?.id ||
|
||||
piece?.typeMachinePieceRequirement?.typePieceId ||
|
||||
piece?.typeMachinePieceRequirement?.typePiece?.id ||
|
||||
structure?.typePieceId ||
|
||||
structureTypePiece?.id ||
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private asRecord(value: unknown): Record<string, any> | null {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
return value as Record<string, any>;
|
||||
}
|
||||
|
||||
private extractCustomFields(structure: Record<string, any> | null): any[] {
|
||||
if (!structure) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { customFields } = structure;
|
||||
return Array.isArray(customFields) ? customFields : [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user