Refactor types service into modular services and repositories
This commit is contained in:
7
src/common/constants/custom-field.constant.ts
Normal file
7
src/common/constants/custom-field.constant.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const CUSTOM_FIELD_SELECT = {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
type: true,
|
||||||
|
required: true,
|
||||||
|
options: true,
|
||||||
|
} as const;
|
||||||
55
src/common/mappers/model-type.mapper.spec.ts
Normal file
55
src/common/mappers/model-type.mapper.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { ModelTypeMapper } from './model-type.mapper';
|
||||||
|
|
||||||
|
describe('ModelTypeMapper', () => {
|
||||||
|
it('should map component create input', () => {
|
||||||
|
const dto = {
|
||||||
|
name: 'Comp',
|
||||||
|
description: 'Desc',
|
||||||
|
customFields: [{ name: 'Field', type: 'string', required: false, options: [] }],
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const input = ModelTypeMapper.toComponentCreateInput(dto, 'code');
|
||||||
|
|
||||||
|
expect(input).toMatchObject({
|
||||||
|
name: 'Comp',
|
||||||
|
code: 'code',
|
||||||
|
description: 'Desc',
|
||||||
|
notes: 'Desc',
|
||||||
|
});
|
||||||
|
expect(input.customFields?.create?.[0]).toMatchObject({ name: 'Field' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map piece model type to DTO shape', () => {
|
||||||
|
const mapped = ModelTypeMapper.mapPieceModelType({
|
||||||
|
id: '1',
|
||||||
|
name: 'Piece',
|
||||||
|
pieceCustomFields: [{ id: 'cf' }],
|
||||||
|
pieceModels: [{ id: 'model' }],
|
||||||
|
pieceRequirements: [{ id: 'req' }],
|
||||||
|
pieces: [{ id: 'piece' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mapped).toMatchObject({
|
||||||
|
id: '1',
|
||||||
|
customFields: [{ id: 'cf' }],
|
||||||
|
models: [{ id: 'model' }],
|
||||||
|
pieceRequirements: [{ id: 'req' }],
|
||||||
|
pieces: [{ id: 'piece' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map piece update input', () => {
|
||||||
|
const input = ModelTypeMapper.toPieceUpdateInput({
|
||||||
|
name: 'New',
|
||||||
|
description: 'D',
|
||||||
|
customFields: [],
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
expect(input).toMatchObject({
|
||||||
|
name: 'New',
|
||||||
|
description: 'D',
|
||||||
|
notes: 'D',
|
||||||
|
});
|
||||||
|
expect(input.pieceCustomFields).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
170
src/common/mappers/model-type.mapper.ts
Normal file
170
src/common/mappers/model-type.mapper.ts
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
import {
|
||||||
|
CreateTypeComposantDto,
|
||||||
|
CreateTypePieceDto,
|
||||||
|
UpdateTypeComposantDto,
|
||||||
|
UpdateTypePieceDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
import { CUSTOM_FIELD_SELECT } from '../constants/custom-field.constant';
|
||||||
|
|
||||||
|
export const COMPONENT_TYPE_INCLUDE: Prisma.ModelTypeInclude = {
|
||||||
|
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||||
|
composants: true,
|
||||||
|
models: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PIECE_TYPE_INCLUDE: Prisma.ModelTypeInclude = {
|
||||||
|
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
||||||
|
pieceModels: true,
|
||||||
|
pieceRequirements: true,
|
||||||
|
pieces: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
type ModelTypeCreateWithoutCategory = Omit<
|
||||||
|
Prisma.ModelTypeCreateInput,
|
||||||
|
'category'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export class ModelTypeMapper {
|
||||||
|
static toComponentCreateInput(
|
||||||
|
dto: CreateTypeComposantDto,
|
||||||
|
code: string,
|
||||||
|
): ModelTypeCreateWithoutCategory {
|
||||||
|
const { customFields, description, name } = dto;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
code,
|
||||||
|
description: description ?? null,
|
||||||
|
notes: description ?? null,
|
||||||
|
customFields: customFields
|
||||||
|
? {
|
||||||
|
create: customFields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static toComponentUpdateInput(
|
||||||
|
dto: UpdateTypeComposantDto,
|
||||||
|
): Prisma.ModelTypeUpdateInput {
|
||||||
|
const { customFields, description, name } = dto;
|
||||||
|
const data: Prisma.ModelTypeUpdateInput = {};
|
||||||
|
|
||||||
|
if (name !== undefined) {
|
||||||
|
data.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description !== undefined) {
|
||||||
|
data.description = description;
|
||||||
|
data.notes = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customFields !== undefined) {
|
||||||
|
data.customFields = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static toPieceCreateInput(
|
||||||
|
dto: CreateTypePieceDto,
|
||||||
|
code: string,
|
||||||
|
): ModelTypeCreateWithoutCategory {
|
||||||
|
const { customFields, description, name } = dto;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
code,
|
||||||
|
description: description ?? null,
|
||||||
|
notes: description ?? null,
|
||||||
|
pieceCustomFields: customFields
|
||||||
|
? {
|
||||||
|
create: customFields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static toPieceUpdateInput(dto: UpdateTypePieceDto): Prisma.ModelTypeUpdateInput {
|
||||||
|
const { customFields, description, name } = dto;
|
||||||
|
const data: Prisma.ModelTypeUpdateInput = {};
|
||||||
|
|
||||||
|
if (name !== undefined) {
|
||||||
|
data.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description !== undefined) {
|
||||||
|
data.description = description;
|
||||||
|
data.notes = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customFields !== undefined) {
|
||||||
|
data.pieceCustomFields = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapPieceModelType(modelType: any) {
|
||||||
|
if (!modelType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
pieceCustomFields,
|
||||||
|
pieceModels,
|
||||||
|
pieceRequirements,
|
||||||
|
pieces,
|
||||||
|
...rest
|
||||||
|
} = modelType;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
customFields: pieceCustomFields ?? [],
|
||||||
|
models: pieceModels ?? [],
|
||||||
|
pieceRequirements: pieceRequirements ?? [],
|
||||||
|
pieces: pieces ?? [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapComponentCustomFieldInputs(
|
||||||
|
fields?: CreateTypeComposantDto['customFields'],
|
||||||
|
) {
|
||||||
|
if (!fields || fields.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapPieceCustomFieldInputs(
|
||||||
|
fields?: CreateTypePieceDto['customFields'],
|
||||||
|
) {
|
||||||
|
if (!fields || fields.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/common/mappers/type-machine.mapper.spec.ts
Normal file
83
src/common/mappers/type-machine.mapper.spec.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { TypeMachineMapper } from './type-machine.mapper';
|
||||||
|
|
||||||
|
const baseDto = {
|
||||||
|
name: 'Machine A',
|
||||||
|
description: 'Desc',
|
||||||
|
customFields: [
|
||||||
|
{ name: 'Field', type: 'string', required: true, options: ['a'] },
|
||||||
|
],
|
||||||
|
componentRequirements: [
|
||||||
|
{
|
||||||
|
label: 'Comp',
|
||||||
|
minCount: 2,
|
||||||
|
maxCount: 4,
|
||||||
|
required: true,
|
||||||
|
allowNewModels: false,
|
||||||
|
typeComposantId: 'comp-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pieceRequirements: [
|
||||||
|
{
|
||||||
|
label: 'Piece',
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 2,
|
||||||
|
required: false,
|
||||||
|
allowNewModels: true,
|
||||||
|
typePieceId: 'piece-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('TypeMachineMapper', () => {
|
||||||
|
it('should map create input with nested relations', () => {
|
||||||
|
const input = TypeMachineMapper.toCreateInput(baseDto as any);
|
||||||
|
|
||||||
|
expect(input.customFields?.create).toHaveLength(1);
|
||||||
|
expect(input.componentRequirements?.create?.[0]).toMatchObject({
|
||||||
|
label: 'Comp',
|
||||||
|
minCount: 2,
|
||||||
|
maxCount: 4,
|
||||||
|
required: true,
|
||||||
|
allowNewModels: false,
|
||||||
|
});
|
||||||
|
expect(input.pieceRequirements?.create?.[0]).toMatchObject({
|
||||||
|
label: 'Piece',
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 2,
|
||||||
|
required: false,
|
||||||
|
allowNewModels: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map custom field inputs for create many', () => {
|
||||||
|
const result = TypeMachineMapper.mapCustomFieldInputs(baseDto.customFields as any);
|
||||||
|
expect(result).toEqual([
|
||||||
|
{
|
||||||
|
name: 'Field',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
options: ['a'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map requirements for bulk insert', () => {
|
||||||
|
const component = TypeMachineMapper.mapComponentRequirementInputs(
|
||||||
|
baseDto.componentRequirements as any,
|
||||||
|
);
|
||||||
|
const piece = TypeMachineMapper.mapPieceRequirementInputs(
|
||||||
|
baseDto.pieceRequirements as any,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(component[0]).toMatchObject({
|
||||||
|
typeComposantId: 'comp-id',
|
||||||
|
minCount: 2,
|
||||||
|
maxCount: 4,
|
||||||
|
});
|
||||||
|
expect(piece[0]).toMatchObject({
|
||||||
|
typePieceId: 'piece-id',
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
188
src/common/mappers/type-machine.mapper.ts
Normal file
188
src/common/mappers/type-machine.mapper.ts
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
import {
|
||||||
|
CreateTypeMachineDto,
|
||||||
|
UpdateTypeMachineDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
import { CUSTOM_FIELD_SELECT } from '../constants/custom-field.constant';
|
||||||
|
|
||||||
|
type RequirementDto = {
|
||||||
|
label?: string | null;
|
||||||
|
minCount?: number | null;
|
||||||
|
maxCount?: number | null;
|
||||||
|
required?: boolean | null;
|
||||||
|
allowNewModels?: boolean | null;
|
||||||
|
typeComposantId?: string;
|
||||||
|
typePieceId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TYPE_MACHINE_DEFAULT_INCLUDE: Prisma.TypeMachineInclude = {
|
||||||
|
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||||
|
componentRequirements: {
|
||||||
|
include: { typeComposant: true },
|
||||||
|
},
|
||||||
|
pieceRequirements: {
|
||||||
|
include: { typePiece: true },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TYPE_MACHINE_WITH_MACHINES_INCLUDE: Prisma.TypeMachineInclude = {
|
||||||
|
...TYPE_MACHINE_DEFAULT_INCLUDE,
|
||||||
|
machines: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class TypeMachineMapper {
|
||||||
|
static toCreateInput(
|
||||||
|
dto: CreateTypeMachineDto,
|
||||||
|
): Prisma.TypeMachineCreateInput {
|
||||||
|
const { customFields, componentRequirements, pieceRequirements, ...data } =
|
||||||
|
dto;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
customFields: this.mapCustomFields(customFields),
|
||||||
|
componentRequirements: this.mapComponentRequirements(componentRequirements),
|
||||||
|
pieceRequirements: this.mapPieceRequirements(pieceRequirements),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static toUpdateData(dto: UpdateTypeMachineDto): Prisma.TypeMachineUpdateInput {
|
||||||
|
const { customFields, componentRequirements, pieceRequirements, ...data } =
|
||||||
|
dto;
|
||||||
|
|
||||||
|
const payload: Prisma.TypeMachineUpdateInput = { ...data };
|
||||||
|
|
||||||
|
if (customFields !== undefined) {
|
||||||
|
payload.customFields = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentRequirements !== undefined) {
|
||||||
|
payload.componentRequirements = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pieceRequirements !== undefined) {
|
||||||
|
payload.pieceRequirements = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapCustomFields(
|
||||||
|
fields?: CreateTypeMachineDto['customFields'],
|
||||||
|
): Prisma.CustomFieldCreateNestedManyWithoutTypeMachineInput | undefined {
|
||||||
|
if (!fields || fields.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: fields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapCustomFieldInputs(
|
||||||
|
fields?: CreateTypeMachineDto['customFields'],
|
||||||
|
) {
|
||||||
|
if (!fields || fields.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields.map((field) => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type,
|
||||||
|
required: field.required ?? false,
|
||||||
|
options: field.options,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapComponentRequirements(
|
||||||
|
requirements?: RequirementDto[] | null,
|
||||||
|
): Prisma.TypeMachineComponentRequirementCreateNestedManyWithoutTypeMachineInput | undefined {
|
||||||
|
if (!requirements || requirements.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: requirements.map((requirement) => ({
|
||||||
|
label: requirement.label ?? null,
|
||||||
|
minCount: requirement.minCount ?? 1,
|
||||||
|
maxCount: requirement.maxCount ?? null,
|
||||||
|
required: requirement.required ?? true,
|
||||||
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
|
typeComposant: requirement.typeComposantId
|
||||||
|
? {
|
||||||
|
connect: { id: requirement.typeComposantId },
|
||||||
|
}
|
||||||
|
: (() => {
|
||||||
|
throw new Error(
|
||||||
|
'typeComposantId est requis pour créer une contrainte de composant.',
|
||||||
|
);
|
||||||
|
})(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapComponentRequirementInputs(
|
||||||
|
requirements?: RequirementDto[] | null,
|
||||||
|
) {
|
||||||
|
if (!requirements || requirements.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return requirements.map((requirement) => ({
|
||||||
|
label: requirement.label ?? null,
|
||||||
|
minCount: requirement.minCount ?? 1,
|
||||||
|
maxCount: requirement.maxCount ?? null,
|
||||||
|
required: requirement.required ?? true,
|
||||||
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
|
typeComposantId: requirement.typeComposantId!,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapPieceRequirements(
|
||||||
|
requirements?: RequirementDto[] | null,
|
||||||
|
): Prisma.TypeMachinePieceRequirementCreateNestedManyWithoutTypeMachineInput | undefined {
|
||||||
|
if (!requirements || requirements.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
create: requirements.map((requirement) => ({
|
||||||
|
label: requirement.label ?? null,
|
||||||
|
minCount: requirement.minCount ?? 0,
|
||||||
|
maxCount: requirement.maxCount ?? null,
|
||||||
|
required: requirement.required ?? false,
|
||||||
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
|
typePiece: requirement.typePieceId
|
||||||
|
? {
|
||||||
|
connect: { id: requirement.typePieceId },
|
||||||
|
}
|
||||||
|
: (() => {
|
||||||
|
throw new Error(
|
||||||
|
'typePieceId est requis pour créer une contrainte de pièce.',
|
||||||
|
);
|
||||||
|
})(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mapPieceRequirementInputs(
|
||||||
|
requirements?: RequirementDto[] | null,
|
||||||
|
) {
|
||||||
|
if (!requirements || requirements.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return requirements.map((requirement) => ({
|
||||||
|
label: requirement.label ?? null,
|
||||||
|
minCount: requirement.minCount ?? 0,
|
||||||
|
maxCount: requirement.maxCount ?? null,
|
||||||
|
required: requirement.required ?? false,
|
||||||
|
allowNewModels: requirement.allowNewModels ?? true,
|
||||||
|
typePieceId: requirement.typePieceId!,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/common/repositories/composant-models.repository.ts
Normal file
58
src/common/repositories/composant-models.repository.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
import { PrismaService } from '../../prisma/prisma.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ComposantModelsRepository {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private get client(): PrismaClient {
|
||||||
|
return this.prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
data: Prisma.ComposantModelCreateInput,
|
||||||
|
include?: Prisma.ComposantModelInclude,
|
||||||
|
) {
|
||||||
|
return this.client.composantModel.create({
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(
|
||||||
|
typeComposantId?: string,
|
||||||
|
include?: Prisma.ComposantModelInclude,
|
||||||
|
) {
|
||||||
|
return this.client.composantModel.findMany({
|
||||||
|
where: typeComposantId ? { typeComposantId } : undefined,
|
||||||
|
include,
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string, include?: Prisma.ComposantModelInclude) {
|
||||||
|
return this.client.composantModel.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.ComposantModelUpdateInput,
|
||||||
|
include?: Prisma.ComposantModelInclude,
|
||||||
|
) {
|
||||||
|
return this.client.composantModel.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string) {
|
||||||
|
return this.client.composantModel.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/common/repositories/model-types.repository.spec.ts
Normal file
71
src/common/repositories/model-types.repository.spec.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { ModelTypesRepository } from './model-types.repository';
|
||||||
|
|
||||||
|
describe('ModelTypesRepository', () => {
|
||||||
|
const prismaMock = {
|
||||||
|
modelType: {
|
||||||
|
findUnique: jest.fn(),
|
||||||
|
create: jest.fn(),
|
||||||
|
findMany: jest.fn(),
|
||||||
|
findFirst: jest.fn(),
|
||||||
|
update: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
},
|
||||||
|
customField: {
|
||||||
|
deleteMany: jest.fn(),
|
||||||
|
createMany: jest.fn(),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const repository = new ModelTypesRepository(prismaMock);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate unique code when conflicts exist', async () => {
|
||||||
|
prismaMock.modelType.findUnique
|
||||||
|
.mockResolvedValueOnce({ id: 'existing' })
|
||||||
|
.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
|
const code = await repository.generateUniqueCode('My Type');
|
||||||
|
|
||||||
|
expect(code).toBe('my-type-1');
|
||||||
|
expect(prismaMock.modelType.findUnique).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create component type custom fields with relation id', async () => {
|
||||||
|
await repository.createComponentTypeCustomFields('comp-id', [
|
||||||
|
{ name: 'Field', type: 'string', required: true, options: [] },
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(prismaMock.customField.createMany).toHaveBeenCalledWith({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: 'Field',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
options: [],
|
||||||
|
typeComposantId: 'comp-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create piece type custom fields with relation id', async () => {
|
||||||
|
await repository.createPieceTypeCustomFields('piece-id', [
|
||||||
|
{ name: 'Field', type: 'string', required: false, options: [] },
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(prismaMock.customField.createMany).toHaveBeenCalledWith({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: 'Field',
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
options: [],
|
||||||
|
typePieceId: 'piece-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
172
src/common/repositories/model-types.repository.ts
Normal file
172
src/common/repositories/model-types.repository.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ModelCategory, Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
import { PrismaService } from '../../prisma/prisma.service';
|
||||||
|
import { slugifyName } from '../utils/slug.util';
|
||||||
|
|
||||||
|
type CustomFieldInput = Omit<
|
||||||
|
Prisma.CustomFieldCreateManyInput,
|
||||||
|
'id' | 'typeMachineId' | 'typePieceId' | 'typeComposantId'
|
||||||
|
>;
|
||||||
|
|
||||||
|
type PieceCustomFieldInput = Omit<
|
||||||
|
Prisma.CustomFieldCreateManyInput,
|
||||||
|
'id' | 'typeMachineId' | 'typePieceId' | 'typeComposantId'
|
||||||
|
>;
|
||||||
|
|
||||||
|
type ModelTypeCreateData = Omit<Prisma.ModelTypeCreateInput, 'category'>;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ModelTypesRepository {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private get client(): PrismaClient {
|
||||||
|
return this.prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateUniqueCode(name: string): Promise<string> {
|
||||||
|
const base = slugifyName(name) || 'type';
|
||||||
|
let candidate = base;
|
||||||
|
let suffix = 1;
|
||||||
|
|
||||||
|
while (await this.client.modelType.findUnique({ where: { code: candidate } })) {
|
||||||
|
candidate = `${base}-${suffix++}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createComponentType(
|
||||||
|
data: ModelTypeCreateData,
|
||||||
|
include?: Prisma.ModelTypeInclude,
|
||||||
|
) {
|
||||||
|
return this.client.modelType.create({
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
category: ModelCategory.COMPONENT,
|
||||||
|
},
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findComponentTypes(include?: Prisma.ModelTypeInclude) {
|
||||||
|
return this.client.modelType.findMany({
|
||||||
|
where: { category: ModelCategory.COMPONENT },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findComponentType(id: string, include?: Prisma.ModelTypeInclude) {
|
||||||
|
return this.client.modelType.findFirst({
|
||||||
|
where: { id, category: ModelCategory.COMPONENT },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateComponentType(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.ModelTypeUpdateInput,
|
||||||
|
include?: Prisma.ModelTypeInclude,
|
||||||
|
) {
|
||||||
|
return this.client.modelType.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteComponentType(id: string) {
|
||||||
|
return this.client.modelType.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteComponentTypeCustomFields(typeComposantId: string) {
|
||||||
|
await this.client.customField.deleteMany({
|
||||||
|
where: { typeComposantId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createComponentTypeCustomFields(
|
||||||
|
typeComposantId: string,
|
||||||
|
customFields: CustomFieldInput[],
|
||||||
|
) {
|
||||||
|
if (!customFields.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.customField.createMany({
|
||||||
|
data: customFields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
typeComposantId,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createPieceType(
|
||||||
|
data: ModelTypeCreateData,
|
||||||
|
include?: Prisma.ModelTypeInclude,
|
||||||
|
) {
|
||||||
|
return this.client.modelType.create({
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
category: ModelCategory.PIECE,
|
||||||
|
},
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findPieceTypes(include?: Prisma.ModelTypeInclude) {
|
||||||
|
return this.client.modelType.findMany({
|
||||||
|
where: { category: ModelCategory.PIECE },
|
||||||
|
include,
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findPieceType(id: string, include?: Prisma.ModelTypeInclude) {
|
||||||
|
return this.client.modelType.findFirst({
|
||||||
|
where: { id, category: ModelCategory.PIECE },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePieceType(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.ModelTypeUpdateInput,
|
||||||
|
include?: Prisma.ModelTypeInclude,
|
||||||
|
) {
|
||||||
|
return this.client.modelType.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deletePieceType(id: string) {
|
||||||
|
return this.client.modelType.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deletePieceTypeCustomFields(typePieceId: string) {
|
||||||
|
await this.client.customField.deleteMany({
|
||||||
|
where: { typePieceId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createPieceTypeCustomFields(
|
||||||
|
typePieceId: string,
|
||||||
|
customFields: PieceCustomFieldInput[],
|
||||||
|
) {
|
||||||
|
if (!customFields.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.customField.createMany({
|
||||||
|
data: customFields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
typePieceId,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/common/repositories/piece-models.repository.ts
Normal file
55
src/common/repositories/piece-models.repository.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
import { PrismaService } from '../../prisma/prisma.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PieceModelsRepository {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private get client(): PrismaClient {
|
||||||
|
return this.prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
data: Prisma.PieceModelCreateInput,
|
||||||
|
include?: Prisma.PieceModelInclude,
|
||||||
|
) {
|
||||||
|
return this.client.pieceModel.create({
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(typePieceId?: string, include?: Prisma.PieceModelInclude) {
|
||||||
|
return this.client.pieceModel.findMany({
|
||||||
|
where: typePieceId ? { typePieceId } : undefined,
|
||||||
|
include,
|
||||||
|
orderBy: { name: 'asc' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string, include?: Prisma.PieceModelInclude) {
|
||||||
|
return this.client.pieceModel.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.PieceModelUpdateInput,
|
||||||
|
include?: Prisma.PieceModelInclude,
|
||||||
|
) {
|
||||||
|
return this.client.pieceModel.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string) {
|
||||||
|
return this.client.pieceModel.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/common/repositories/type-machines.repository.spec.ts
Normal file
117
src/common/repositories/type-machines.repository.spec.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { TypeMachinesRepository } from './type-machines.repository';
|
||||||
|
|
||||||
|
describe('TypeMachinesRepository', () => {
|
||||||
|
const prismaMock = {
|
||||||
|
customField: {
|
||||||
|
deleteMany: jest.fn(),
|
||||||
|
createMany: jest.fn(),
|
||||||
|
},
|
||||||
|
typeMachineComponentRequirement: {
|
||||||
|
deleteMany: jest.fn(),
|
||||||
|
createMany: jest.fn(),
|
||||||
|
},
|
||||||
|
typeMachinePieceRequirement: {
|
||||||
|
deleteMany: jest.fn(),
|
||||||
|
createMany: jest.fn(),
|
||||||
|
},
|
||||||
|
machine: {
|
||||||
|
findMany: jest.fn().mockResolvedValue([{ id: '1', name: 'Machine' }]),
|
||||||
|
},
|
||||||
|
typeMachine: {
|
||||||
|
create: jest.fn(),
|
||||||
|
findMany: jest.fn(),
|
||||||
|
findUnique: jest.fn(),
|
||||||
|
update: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const repository = new TypeMachinesRepository(prismaMock);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should append typeMachineId when creating custom fields', async () => {
|
||||||
|
await repository.createCustomFields('machine-id', [
|
||||||
|
{ name: 'Field', type: 'string', required: true, options: [] },
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(prismaMock.customField.createMany).toHaveBeenCalledWith({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: 'Field',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
options: [],
|
||||||
|
typeMachineId: 'machine-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should append typeMachineId when creating component requirements', async () => {
|
||||||
|
await repository.createComponentRequirements('machine-id', [
|
||||||
|
{
|
||||||
|
label: 'Comp',
|
||||||
|
minCount: 1,
|
||||||
|
maxCount: 2,
|
||||||
|
required: true,
|
||||||
|
allowNewModels: true,
|
||||||
|
typeComposantId: 'comp',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
prismaMock.typeMachineComponentRequirement.createMany,
|
||||||
|
).toHaveBeenCalledWith({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
label: 'Comp',
|
||||||
|
minCount: 1,
|
||||||
|
maxCount: 2,
|
||||||
|
required: true,
|
||||||
|
allowNewModels: true,
|
||||||
|
typeComposantId: 'comp',
|
||||||
|
typeMachineId: 'machine-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should append typeMachineId when creating piece requirements', async () => {
|
||||||
|
await repository.createPieceRequirements('machine-id', [
|
||||||
|
{
|
||||||
|
label: 'Piece',
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 1,
|
||||||
|
required: false,
|
||||||
|
allowNewModels: true,
|
||||||
|
typePieceId: 'piece',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(prismaMock.typeMachinePieceRequirement.createMany).toHaveBeenCalledWith({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
label: 'Piece',
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 1,
|
||||||
|
required: false,
|
||||||
|
allowNewModels: true,
|
||||||
|
typePieceId: 'piece',
|
||||||
|
typeMachineId: 'machine-id',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find machines using type', async () => {
|
||||||
|
const result = await repository.findMachinesUsingType('machine-id');
|
||||||
|
expect(result).toEqual([{ id: '1', name: 'Machine' }]);
|
||||||
|
expect(prismaMock.machine.findMany).toHaveBeenCalledWith({
|
||||||
|
where: { typeMachineId: 'machine-id' },
|
||||||
|
select: { id: true, name: true },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
141
src/common/repositories/type-machines.repository.ts
Normal file
141
src/common/repositories/type-machines.repository.ts
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Prisma, PrismaClient } from '@prisma/client';
|
||||||
|
import { PrismaService } from '../../prisma/prisma.service';
|
||||||
|
|
||||||
|
type CustomFieldInput = Omit<
|
||||||
|
Prisma.CustomFieldCreateManyInput,
|
||||||
|
'id' | 'typeMachineId' | 'typePieceId' | 'typeComposantId'
|
||||||
|
>;
|
||||||
|
|
||||||
|
type ComponentRequirementInput = Omit<
|
||||||
|
Prisma.TypeMachineComponentRequirementCreateManyInput,
|
||||||
|
'id' | 'typeMachineId'
|
||||||
|
>;
|
||||||
|
|
||||||
|
type PieceRequirementInput = Omit<
|
||||||
|
Prisma.TypeMachinePieceRequirementCreateManyInput,
|
||||||
|
'id' | 'typeMachineId'
|
||||||
|
>;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TypeMachinesRepository {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
private get client(): PrismaClient {
|
||||||
|
return this.prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
data: Prisma.TypeMachineCreateInput,
|
||||||
|
include?: Prisma.TypeMachineInclude,
|
||||||
|
) {
|
||||||
|
return this.client.typeMachine.create({
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(include?: Prisma.TypeMachineInclude) {
|
||||||
|
return this.client.typeMachine.findMany({
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string, include?: Prisma.TypeMachineInclude) {
|
||||||
|
return this.client.typeMachine.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
id: string,
|
||||||
|
data: Prisma.TypeMachineUpdateInput,
|
||||||
|
include?: Prisma.TypeMachineInclude,
|
||||||
|
) {
|
||||||
|
return this.client.typeMachine.update({
|
||||||
|
where: { id },
|
||||||
|
data,
|
||||||
|
include,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string) {
|
||||||
|
return this.client.typeMachine.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteCustomFields(typeMachineId: string) {
|
||||||
|
await this.client.customField.deleteMany({
|
||||||
|
where: { typeMachineId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createCustomFields(
|
||||||
|
typeMachineId: string,
|
||||||
|
customFields: CustomFieldInput[],
|
||||||
|
) {
|
||||||
|
if (!customFields.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.customField.createMany({
|
||||||
|
data: customFields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
typeMachineId,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteComponentRequirements(typeMachineId: string) {
|
||||||
|
await this.client.typeMachineComponentRequirement.deleteMany({
|
||||||
|
where: { typeMachineId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createComponentRequirements(
|
||||||
|
typeMachineId: string,
|
||||||
|
requirements: ComponentRequirementInput[],
|
||||||
|
) {
|
||||||
|
if (!requirements.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.typeMachineComponentRequirement.createMany({
|
||||||
|
data: requirements.map((requirement) => ({
|
||||||
|
...requirement,
|
||||||
|
typeMachineId,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deletePieceRequirements(typeMachineId: string) {
|
||||||
|
await this.client.typeMachinePieceRequirement.deleteMany({
|
||||||
|
where: { typeMachineId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async createPieceRequirements(
|
||||||
|
typeMachineId: string,
|
||||||
|
requirements: PieceRequirementInput[],
|
||||||
|
) {
|
||||||
|
if (!requirements.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.typeMachinePieceRequirement.createMany({
|
||||||
|
data: requirements.map((requirement) => ({
|
||||||
|
...requirement,
|
||||||
|
typeMachineId,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findMachinesUsingType(typeMachineId: string) {
|
||||||
|
return this.client.machine.findMany({
|
||||||
|
where: { typeMachineId },
|
||||||
|
select: { id: true, name: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/common/utils/slug.util.ts
Normal file
9
src/common/utils/slug.util.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function slugifyName(name: string): string {
|
||||||
|
return name
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
.replace(/-+/g, '-');
|
||||||
|
}
|
||||||
53
src/types/services/composant-model.service.ts
Normal file
53
src/types/services/composant-model.service.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ComposantModelsRepository } from '../../common/repositories/composant-models.repository';
|
||||||
|
import {
|
||||||
|
CreateComposantModelDto,
|
||||||
|
UpdateComposantModelDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
|
||||||
|
const COMPOSANT_MODEL_INCLUDE = {
|
||||||
|
typeComposant: true,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ComposantModelService {
|
||||||
|
constructor(private readonly repository: ComposantModelsRepository) {}
|
||||||
|
|
||||||
|
async create(dto: CreateComposantModelDto) {
|
||||||
|
const { typeComposantId, ...data } = dto;
|
||||||
|
return this.repository.create(
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
typeComposant: { connect: { id: typeComposantId } },
|
||||||
|
},
|
||||||
|
COMPOSANT_MODEL_INCLUDE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(typeComposantId?: string) {
|
||||||
|
return this.repository.findAll(typeComposantId, COMPOSANT_MODEL_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
return this.repository.findOne(id, COMPOSANT_MODEL_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateComposantModelDto) {
|
||||||
|
const { typeComposantId, ...data } = dto;
|
||||||
|
|
||||||
|
return this.repository.update(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
...(typeComposantId
|
||||||
|
? { typeComposant: { connect: { id: typeComposantId } } }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
COMPOSANT_MODEL_INCLUDE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
return this.repository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/types/services/piece-model.service.ts
Normal file
49
src/types/services/piece-model.service.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PieceModelsRepository } from '../../common/repositories/piece-models.repository';
|
||||||
|
import { CreatePieceModelDto, UpdatePieceModelDto } from '../../shared/dto/type.dto';
|
||||||
|
|
||||||
|
const PIECE_MODEL_INCLUDE = {
|
||||||
|
typePiece: true,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PieceModelService {
|
||||||
|
constructor(private readonly repository: PieceModelsRepository) {}
|
||||||
|
|
||||||
|
async create(dto: CreatePieceModelDto) {
|
||||||
|
const { typePieceId, ...data } = dto;
|
||||||
|
|
||||||
|
return this.repository.create(
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
typePiece: { connect: { id: typePieceId } },
|
||||||
|
},
|
||||||
|
PIECE_MODEL_INCLUDE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(typePieceId?: string) {
|
||||||
|
return this.repository.findAll(typePieceId, PIECE_MODEL_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
return this.repository.findOne(id, PIECE_MODEL_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdatePieceModelDto) {
|
||||||
|
const { typePieceId, ...data } = dto;
|
||||||
|
|
||||||
|
return this.repository.update(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
...data,
|
||||||
|
...(typePieceId ? { typePiece: { connect: { id: typePieceId } } } : {}),
|
||||||
|
},
|
||||||
|
PIECE_MODEL_INCLUDE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
return this.repository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/types/services/type-component.service.ts
Normal file
47
src/types/services/type-component.service.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ModelTypesRepository } from '../../common/repositories/model-types.repository';
|
||||||
|
import {
|
||||||
|
COMPONENT_TYPE_INCLUDE,
|
||||||
|
ModelTypeMapper,
|
||||||
|
} from '../../common/mappers/model-type.mapper';
|
||||||
|
import {
|
||||||
|
CreateTypeComposantDto,
|
||||||
|
UpdateTypeComposantDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TypeComponentService {
|
||||||
|
constructor(private readonly repository: ModelTypesRepository) {}
|
||||||
|
|
||||||
|
async create(dto: CreateTypeComposantDto) {
|
||||||
|
const code = await this.repository.generateUniqueCode(dto.name);
|
||||||
|
const data = ModelTypeMapper.toComponentCreateInput(dto, code);
|
||||||
|
|
||||||
|
return this.repository.createComponentType(data, COMPONENT_TYPE_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll() {
|
||||||
|
return this.repository.findComponentTypes(COMPONENT_TYPE_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
return this.repository.findComponentType(id, COMPONENT_TYPE_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateTypeComposantDto) {
|
||||||
|
if (dto.customFields !== undefined) {
|
||||||
|
await this.repository.deleteComponentTypeCustomFields(id);
|
||||||
|
const fields = ModelTypeMapper.mapComponentCustomFieldInputs(
|
||||||
|
dto.customFields,
|
||||||
|
);
|
||||||
|
await this.repository.createComponentTypeCustomFields(id, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = ModelTypeMapper.toComponentUpdateInput(dto);
|
||||||
|
return this.repository.updateComponentType(id, data, COMPONENT_TYPE_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
return this.repository.deleteComponentType(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/types/services/type-machine.service.ts
Normal file
72
src/types/services/type-machine.service.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { TypeMachinesRepository } from '../../common/repositories/type-machines.repository';
|
||||||
|
import {
|
||||||
|
TYPE_MACHINE_DEFAULT_INCLUDE,
|
||||||
|
TYPE_MACHINE_WITH_MACHINES_INCLUDE,
|
||||||
|
TypeMachineMapper,
|
||||||
|
} from '../../common/mappers/type-machine.mapper';
|
||||||
|
import {
|
||||||
|
CreateTypeMachineDto,
|
||||||
|
UpdateTypeMachineDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TypeMachineService {
|
||||||
|
constructor(private readonly repository: TypeMachinesRepository) {}
|
||||||
|
|
||||||
|
async create(dto: CreateTypeMachineDto) {
|
||||||
|
const data = TypeMachineMapper.toCreateInput(dto);
|
||||||
|
|
||||||
|
return this.repository.create(data, TYPE_MACHINE_DEFAULT_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll() {
|
||||||
|
return this.repository.findAll(TYPE_MACHINE_WITH_MACHINES_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
return this.repository.findOne(id, TYPE_MACHINE_WITH_MACHINES_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateTypeMachineDto) {
|
||||||
|
const updateData = TypeMachineMapper.toUpdateData(dto);
|
||||||
|
|
||||||
|
if (dto.customFields !== undefined) {
|
||||||
|
await this.repository.deleteCustomFields(id);
|
||||||
|
const fields = TypeMachineMapper.mapCustomFieldInputs(dto.customFields);
|
||||||
|
await this.repository.createCustomFields(id, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.componentRequirements !== undefined) {
|
||||||
|
await this.repository.deleteComponentRequirements(id);
|
||||||
|
const requirements = TypeMachineMapper.mapComponentRequirementInputs(
|
||||||
|
dto.componentRequirements,
|
||||||
|
);
|
||||||
|
await this.repository.createComponentRequirements(id, requirements);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.pieceRequirements !== undefined) {
|
||||||
|
await this.repository.deletePieceRequirements(id);
|
||||||
|
const requirements = TypeMachineMapper.mapPieceRequirementInputs(
|
||||||
|
dto.pieceRequirements,
|
||||||
|
);
|
||||||
|
await this.repository.createPieceRequirements(id, requirements);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.repository.update(id, updateData, TYPE_MACHINE_DEFAULT_INCLUDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
const machines = await this.repository.findMachinesUsingType(id);
|
||||||
|
|
||||||
|
if (machines.length > 0) {
|
||||||
|
const names = machines.map((machine) => machine.name).join(', ');
|
||||||
|
throw new Error(
|
||||||
|
`Impossible de supprimer ce type de machine car il est utilisé par ${machines.length} machine(s): ${names}. Veuillez d'abord supprimer ou modifier ces machines.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.repository.deleteCustomFields(id);
|
||||||
|
return this.repository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/types/services/type-piece.service.ts
Normal file
54
src/types/services/type-piece.service.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ModelTypesRepository } from '../../common/repositories/model-types.repository';
|
||||||
|
import {
|
||||||
|
ModelTypeMapper,
|
||||||
|
PIECE_TYPE_INCLUDE,
|
||||||
|
} from '../../common/mappers/model-type.mapper';
|
||||||
|
import {
|
||||||
|
CreateTypePieceDto,
|
||||||
|
UpdateTypePieceDto,
|
||||||
|
} from '../../shared/dto/type.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TypePieceService {
|
||||||
|
constructor(private readonly repository: ModelTypesRepository) {}
|
||||||
|
|
||||||
|
async create(dto: CreateTypePieceDto) {
|
||||||
|
const code = await this.repository.generateUniqueCode(dto.name);
|
||||||
|
const data = ModelTypeMapper.toPieceCreateInput(dto, code);
|
||||||
|
|
||||||
|
const created = await this.repository.createPieceType(data, PIECE_TYPE_INCLUDE);
|
||||||
|
return ModelTypeMapper.mapPieceModelType(created);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll() {
|
||||||
|
const items = await this.repository.findPieceTypes(PIECE_TYPE_INCLUDE);
|
||||||
|
return items.map((item) => ModelTypeMapper.mapPieceModelType(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: string) {
|
||||||
|
const item = await this.repository.findPieceType(id, PIECE_TYPE_INCLUDE);
|
||||||
|
return ModelTypeMapper.mapPieceModelType(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateTypePieceDto) {
|
||||||
|
if (dto.customFields !== undefined) {
|
||||||
|
await this.repository.deletePieceTypeCustomFields(id);
|
||||||
|
const fields = ModelTypeMapper.mapPieceCustomFieldInputs(dto.customFields);
|
||||||
|
await this.repository.createPieceTypeCustomFields(id, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = ModelTypeMapper.toPieceUpdateInput(dto);
|
||||||
|
const updated = await this.repository.updatePieceType(
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
PIECE_TYPE_INCLUDE,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ModelTypeMapper.mapPieceModelType(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string) {
|
||||||
|
return this.repository.deletePieceType(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,15 @@ import { Test, TestingModule } from '@nestjs/testing';
|
|||||||
import { TypesController } from './types.controller';
|
import { TypesController } from './types.controller';
|
||||||
import { TypesService } from './types.service';
|
import { TypesService } from './types.service';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { TypeMachineService } from './services/type-machine.service';
|
||||||
|
import { TypeComponentService } from './services/type-component.service';
|
||||||
|
import { TypePieceService } from './services/type-piece.service';
|
||||||
|
import { ComposantModelService } from './services/composant-model.service';
|
||||||
|
import { PieceModelService } from './services/piece-model.service';
|
||||||
|
import { TypeMachinesRepository } from '../common/repositories/type-machines.repository';
|
||||||
|
import { ModelTypesRepository } from '../common/repositories/model-types.repository';
|
||||||
|
import { ComposantModelsRepository } from '../common/repositories/composant-models.repository';
|
||||||
|
import { PieceModelsRepository } from '../common/repositories/piece-models.repository';
|
||||||
|
|
||||||
describe('TypesController', () => {
|
describe('TypesController', () => {
|
||||||
let controller: TypesController;
|
let controller: TypesController;
|
||||||
@@ -9,7 +18,19 @@ describe('TypesController', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
controllers: [TypesController],
|
controllers: [TypesController],
|
||||||
providers: [TypesService, PrismaService],
|
providers: [
|
||||||
|
TypesService,
|
||||||
|
TypeMachineService,
|
||||||
|
TypeComponentService,
|
||||||
|
TypePieceService,
|
||||||
|
ComposantModelService,
|
||||||
|
PieceModelService,
|
||||||
|
TypeMachinesRepository,
|
||||||
|
ModelTypesRepository,
|
||||||
|
ComposantModelsRepository,
|
||||||
|
PieceModelsRepository,
|
||||||
|
PrismaService,
|
||||||
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
controller = module.get<TypesController>(TypesController);
|
controller = module.get<TypesController>(TypesController);
|
||||||
|
|||||||
@@ -1,9 +1,29 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ComposantModelsRepository } from '../common/repositories/composant-models.repository';
|
||||||
|
import { ModelTypesRepository } from '../common/repositories/model-types.repository';
|
||||||
|
import { PieceModelsRepository } from '../common/repositories/piece-models.repository';
|
||||||
|
import { TypeMachinesRepository } from '../common/repositories/type-machines.repository';
|
||||||
import { TypesController } from './types.controller';
|
import { TypesController } from './types.controller';
|
||||||
import { TypesService } from './types.service';
|
import { TypesService } from './types.service';
|
||||||
|
import { ComposantModelService } from './services/composant-model.service';
|
||||||
|
import { PieceModelService } from './services/piece-model.service';
|
||||||
|
import { TypeComponentService } from './services/type-component.service';
|
||||||
|
import { TypeMachineService } from './services/type-machine.service';
|
||||||
|
import { TypePieceService } from './services/type-piece.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [TypesController],
|
controllers: [TypesController],
|
||||||
providers: [TypesService],
|
providers: [
|
||||||
|
TypesService,
|
||||||
|
TypeMachineService,
|
||||||
|
TypeComponentService,
|
||||||
|
TypePieceService,
|
||||||
|
ComposantModelService,
|
||||||
|
PieceModelService,
|
||||||
|
TypeMachinesRepository,
|
||||||
|
ModelTypesRepository,
|
||||||
|
ComposantModelsRepository,
|
||||||
|
PieceModelsRepository,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class TypesModule {}
|
export class TypesModule {}
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { TypesService } from './types.service';
|
import { TypesService } from './types.service';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { TypeMachineService } from './services/type-machine.service';
|
||||||
|
import { TypeComponentService } from './services/type-component.service';
|
||||||
|
import { TypePieceService } from './services/type-piece.service';
|
||||||
|
import { ComposantModelService } from './services/composant-model.service';
|
||||||
|
import { PieceModelService } from './services/piece-model.service';
|
||||||
|
import { TypeMachinesRepository } from '../common/repositories/type-machines.repository';
|
||||||
|
import { ModelTypesRepository } from '../common/repositories/model-types.repository';
|
||||||
|
import { ComposantModelsRepository } from '../common/repositories/composant-models.repository';
|
||||||
|
import { PieceModelsRepository } from '../common/repositories/piece-models.repository';
|
||||||
|
|
||||||
describe('TypesService', () => {
|
describe('TypesService', () => {
|
||||||
let service: TypesService;
|
let service: TypesService;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [TypesService, PrismaService],
|
providers: [
|
||||||
|
TypesService,
|
||||||
|
TypeMachineService,
|
||||||
|
TypeComponentService,
|
||||||
|
TypePieceService,
|
||||||
|
ComposantModelService,
|
||||||
|
PieceModelService,
|
||||||
|
TypeMachinesRepository,
|
||||||
|
ModelTypesRepository,
|
||||||
|
ComposantModelsRepository,
|
||||||
|
PieceModelsRepository,
|
||||||
|
PrismaService,
|
||||||
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<TypesService>(TypesService);
|
service = module.get<TypesService>(TypesService);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ModelCategory } from '@prisma/client';
|
import { ComposantModelService } from './services/composant-model.service';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PieceModelService } from './services/piece-model.service';
|
||||||
|
import { TypeComponentService } from './services/type-component.service';
|
||||||
|
import { TypeMachineService } from './services/type-machine.service';
|
||||||
|
import { TypePieceService } from './services/type-piece.service';
|
||||||
import {
|
import {
|
||||||
CreateTypeMachineDto,
|
CreateTypeMachineDto,
|
||||||
UpdateTypeMachineDto,
|
UpdateTypeMachineDto,
|
||||||
@@ -14,640 +17,118 @@ import {
|
|||||||
UpdatePieceModelDto,
|
UpdatePieceModelDto,
|
||||||
} from '../shared/dto/type.dto';
|
} from '../shared/dto/type.dto';
|
||||||
|
|
||||||
const CUSTOM_FIELD_SELECT = {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
type: true,
|
|
||||||
required: true,
|
|
||||||
options: true,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TypesService {
|
export class TypesService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(
|
||||||
|
private readonly typeMachineService: TypeMachineService,
|
||||||
|
private readonly typeComponentService: TypeComponentService,
|
||||||
|
private readonly typePieceService: TypePieceService,
|
||||||
|
private readonly composantModelService: ComposantModelService,
|
||||||
|
private readonly pieceModelService: PieceModelService,
|
||||||
|
) {}
|
||||||
|
|
||||||
private slugifyName(name: string): string {
|
// TypeMachine
|
||||||
return name
|
createTypeMachine(dto: CreateTypeMachineDto) {
|
||||||
.normalize('NFD')
|
return this.typeMachineService.create(dto);
|
||||||
.replace(/[\u0300-\u036f]/g, '')
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9]+/g, '-')
|
|
||||||
.replace(/^-+|-+$/g, '')
|
|
||||||
.replace(/-+/g, '-');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async generateUniqueModelTypeCode(name: string): Promise<string> {
|
findAllTypeMachines() {
|
||||||
const base = this.slugifyName(name) || 'type';
|
return this.typeMachineService.findAll();
|
||||||
let candidate = base;
|
|
||||||
let suffix = 1;
|
|
||||||
|
|
||||||
while (
|
|
||||||
await this.prisma.modelType.findUnique({
|
|
||||||
where: { code: candidate },
|
|
||||||
select: { id: true },
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
candidate = `${base}-${suffix++}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return candidate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeMachine methods
|
findOneTypeMachine(id: string) {
|
||||||
async createTypeMachine(createTypeMachineDto: CreateTypeMachineDto) {
|
return this.typeMachineService.findOne(id);
|
||||||
const {
|
|
||||||
customFields,
|
|
||||||
componentRequirements,
|
|
||||||
pieceRequirements,
|
|
||||||
...typeData
|
|
||||||
} = createTypeMachineDto;
|
|
||||||
|
|
||||||
return this.prisma.typeMachine.create({
|
|
||||||
data: {
|
|
||||||
...typeData,
|
|
||||||
customFields: customFields
|
|
||||||
? {
|
|
||||||
create: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
componentRequirements:
|
|
||||||
componentRequirements && componentRequirements.length > 0
|
|
||||||
? {
|
|
||||||
create: componentRequirements.map((requirement) => ({
|
|
||||||
label: requirement.label,
|
|
||||||
minCount: requirement.minCount ?? 1,
|
|
||||||
maxCount: requirement.maxCount ?? null,
|
|
||||||
required: requirement.required ?? true,
|
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
|
||||||
typeComposant: {
|
|
||||||
connect: { id: requirement.typeComposantId },
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
pieceRequirements:
|
|
||||||
pieceRequirements && pieceRequirements.length > 0
|
|
||||||
? {
|
|
||||||
create: pieceRequirements.map((requirement) => ({
|
|
||||||
label: requirement.label,
|
|
||||||
minCount: requirement.minCount ?? 0,
|
|
||||||
maxCount: requirement.maxCount ?? null,
|
|
||||||
required: requirement.required ?? false,
|
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
|
||||||
typePiece: {
|
|
||||||
connect: { id: requirement.typePieceId },
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
componentRequirements: {
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pieceRequirements: {
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllTypeMachines() {
|
updateTypeMachine(id: string, dto: UpdateTypeMachineDto) {
|
||||||
return this.prisma.typeMachine.findMany({
|
return this.typeMachineService.update(id, dto);
|
||||||
include: {
|
|
||||||
machines: true,
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
componentRequirements: {
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pieceRequirements: {
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneTypeMachine(id: string) {
|
removeTypeMachine(id: string) {
|
||||||
return this.prisma.typeMachine.findUnique({
|
return this.typeMachineService.remove(id);
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
machines: true,
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
componentRequirements: {
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pieceRequirements: {
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypeMachine(
|
// TypeComposant
|
||||||
id: string,
|
createTypeComposant(dto: CreateTypeComposantDto) {
|
||||||
updateTypeMachineDto: UpdateTypeMachineDto,
|
return this.typeComponentService.create(dto);
|
||||||
) {
|
|
||||||
const {
|
|
||||||
customFields,
|
|
||||||
componentRequirements,
|
|
||||||
pieceRequirements,
|
|
||||||
...typeData
|
|
||||||
} = updateTypeMachineDto;
|
|
||||||
|
|
||||||
// Si des champs personnalisés sont fournis, on les met à jour
|
|
||||||
if (customFields !== undefined) {
|
|
||||||
// Supprimer tous les champs personnalisés existants
|
|
||||||
await this.prisma.customField.deleteMany({
|
|
||||||
where: { typeMachineId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Créer les nouveaux champs personnalisés
|
|
||||||
if (customFields.length > 0) {
|
|
||||||
await this.prisma.customField.createMany({
|
|
||||||
data: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
typeMachineId: id,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (componentRequirements !== undefined) {
|
|
||||||
await this.prisma.typeMachineComponentRequirement.deleteMany({
|
|
||||||
where: { typeMachineId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (componentRequirements.length > 0) {
|
|
||||||
await this.prisma.typeMachineComponentRequirement.createMany({
|
|
||||||
data: componentRequirements.map((requirement) => ({
|
|
||||||
label: requirement.label ?? null,
|
|
||||||
minCount: requirement.minCount ?? 1,
|
|
||||||
maxCount: requirement.maxCount ?? null,
|
|
||||||
required: requirement.required ?? true,
|
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
|
||||||
typeMachineId: id,
|
|
||||||
typeComposantId: requirement.typeComposantId,
|
|
||||||
})),
|
|
||||||
skipDuplicates: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pieceRequirements !== undefined) {
|
|
||||||
await this.prisma.typeMachinePieceRequirement.deleteMany({
|
|
||||||
where: { typeMachineId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pieceRequirements.length > 0) {
|
|
||||||
await this.prisma.typeMachinePieceRequirement.createMany({
|
|
||||||
data: pieceRequirements.map((requirement) => ({
|
|
||||||
label: requirement.label ?? null,
|
|
||||||
minCount: requirement.minCount ?? 0,
|
|
||||||
maxCount: requirement.maxCount ?? null,
|
|
||||||
required: requirement.required ?? false,
|
|
||||||
allowNewModels: requirement.allowNewModels ?? true,
|
|
||||||
typeMachineId: id,
|
|
||||||
typePieceId: requirement.typePieceId,
|
|
||||||
})),
|
|
||||||
skipDuplicates: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.prisma.typeMachine.update({
|
|
||||||
where: { id },
|
|
||||||
data: typeData,
|
|
||||||
include: {
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
componentRequirements: {
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pieceRequirements: {
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeTypeMachine(id: string) {
|
findAllTypeComposants() {
|
||||||
// Vérifier s'il y a des machines liées à ce type
|
return this.typeComponentService.findAll();
|
||||||
const machinesWithType = await this.prisma.machine.findMany({
|
|
||||||
where: { typeMachineId: id },
|
|
||||||
select: { id: true, name: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (machinesWithType.length > 0) {
|
|
||||||
const machineNames = machinesWithType.map((m) => m.name).join(', ');
|
|
||||||
throw new Error(
|
|
||||||
`Impossible de supprimer ce type de machine car il est utilisé par ${machinesWithType.length} machine(s): ${machineNames}. ` +
|
|
||||||
`Veuillez d'abord supprimer ou modifier ces machines.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supprimer les champs personnalisés associés
|
|
||||||
await this.prisma.customField.deleteMany({
|
|
||||||
where: { typeMachineId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.prisma.typeMachine.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeComposant methods (backed by ModelType with COMPONENT category)
|
findOneTypeComposant(id: string) {
|
||||||
async createTypeComposant(createTypeComposantDto: CreateTypeComposantDto) {
|
return this.typeComponentService.findOne(id);
|
||||||
const { customFields, description, name } = createTypeComposantDto;
|
|
||||||
|
|
||||||
const code = await this.generateUniqueModelTypeCode(name);
|
|
||||||
|
|
||||||
return this.prisma.modelType.create({
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
code,
|
|
||||||
category: ModelCategory.COMPONENT,
|
|
||||||
description: description ?? null,
|
|
||||||
notes: description ?? null,
|
|
||||||
customFields: customFields
|
|
||||||
? {
|
|
||||||
create: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllTypeComposants() {
|
updateTypeComposant(id: string, dto: UpdateTypeComposantDto) {
|
||||||
return this.prisma.modelType.findMany({
|
return this.typeComponentService.update(id, dto);
|
||||||
where: { category: ModelCategory.COMPONENT },
|
|
||||||
include: {
|
|
||||||
composants: true,
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
models: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneTypeComposant(id: string) {
|
removeTypeComposant(id: string) {
|
||||||
return this.prisma.modelType.findFirst({
|
return this.typeComponentService.remove(id);
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
category: ModelCategory.COMPONENT,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
composants: true,
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
models: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypeComposant(
|
// TypePiece
|
||||||
id: string,
|
createTypePiece(dto: CreateTypePieceDto) {
|
||||||
updateTypeComposantDto: UpdateTypeComposantDto,
|
return this.typePieceService.create(dto);
|
||||||
) {
|
|
||||||
const { customFields, description, name } = updateTypeComposantDto;
|
|
||||||
|
|
||||||
if (customFields !== undefined) {
|
|
||||||
await this.prisma.customField.deleteMany({
|
|
||||||
where: { typeComposantId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (customFields.length > 0) {
|
|
||||||
await this.prisma.customField.createMany({
|
|
||||||
data: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
typeComposantId: id,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const data: Record<string, unknown> = {};
|
|
||||||
if (name !== undefined) {
|
|
||||||
data.name = name;
|
|
||||||
}
|
|
||||||
if (description !== undefined) {
|
|
||||||
data.description = description;
|
|
||||||
data.notes = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.prisma.modelType.update({
|
|
||||||
where: { id },
|
|
||||||
data,
|
|
||||||
include: {
|
|
||||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeTypeComposant(id: string) {
|
findAllTypePieces() {
|
||||||
return this.prisma.modelType.delete({
|
return this.typePieceService.findAll();
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypePiece methods backed by ModelType
|
findOneTypePiece(id: string) {
|
||||||
private mapModelTypePiece(modelType: any) {
|
return this.typePieceService.findOne(id);
|
||||||
if (!modelType) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
pieceCustomFields,
|
|
||||||
pieceModels,
|
|
||||||
pieceRequirements,
|
|
||||||
pieces,
|
|
||||||
...rest
|
|
||||||
} = modelType;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...rest,
|
|
||||||
customFields: pieceCustomFields ?? [],
|
|
||||||
models: pieceModels ?? [],
|
|
||||||
pieceRequirements: pieceRequirements ?? [],
|
|
||||||
pieces: pieces ?? [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async createTypePiece(createTypePieceDto: CreateTypePieceDto) {
|
updateTypePiece(id: string, dto: UpdateTypePieceDto) {
|
||||||
const { customFields, description, name } = createTypePieceDto;
|
return this.typePieceService.update(id, dto);
|
||||||
|
|
||||||
const code = await this.generateUniqueModelTypeCode(name);
|
|
||||||
|
|
||||||
const created = await this.prisma.modelType.create({
|
|
||||||
data: {
|
|
||||||
name,
|
|
||||||
code,
|
|
||||||
category: ModelCategory.PIECE,
|
|
||||||
description: description ?? null,
|
|
||||||
notes: description ?? null,
|
|
||||||
pieceCustomFields: customFields
|
|
||||||
? {
|
|
||||||
create: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
pieceModels: true,
|
|
||||||
pieceRequirements: true,
|
|
||||||
pieces: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.mapModelTypePiece(created);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllTypePieces() {
|
removeTypePiece(id: string) {
|
||||||
const items = await this.prisma.modelType.findMany({
|
return this.typePieceService.remove(id);
|
||||||
where: { category: ModelCategory.PIECE },
|
|
||||||
include: {
|
|
||||||
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
pieceModels: true,
|
|
||||||
pieceRequirements: true,
|
|
||||||
pieces: true,
|
|
||||||
},
|
|
||||||
orderBy: { name: 'asc' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return items.map((item) => this.mapModelTypePiece(item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneTypePiece(id: string) {
|
// ComposantModel
|
||||||
const item = await this.prisma.modelType.findFirst({
|
createComposantModel(dto: CreateComposantModelDto) {
|
||||||
where: { id, category: ModelCategory.PIECE },
|
return this.composantModelService.create(dto);
|
||||||
include: {
|
|
||||||
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
pieceModels: true,
|
|
||||||
pieceRequirements: true,
|
|
||||||
pieces: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.mapModelTypePiece(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTypePiece(id: string, updateTypePieceDto: UpdateTypePieceDto) {
|
findAllComposantModels(typeComposantId?: string) {
|
||||||
const { customFields, description, name } = updateTypePieceDto;
|
return this.composantModelService.findAll(typeComposantId);
|
||||||
|
|
||||||
if (customFields !== undefined) {
|
|
||||||
await this.prisma.customField.deleteMany({
|
|
||||||
where: { typePieceId: id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (customFields.length > 0) {
|
|
||||||
await this.prisma.customField.createMany({
|
|
||||||
data: customFields.map((field) => ({
|
|
||||||
name: field.name,
|
|
||||||
type: field.type,
|
|
||||||
required: field.required || false,
|
|
||||||
options: field.options,
|
|
||||||
typePieceId: id,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatePayload: Record<string, unknown> = {};
|
|
||||||
if (name !== undefined) {
|
|
||||||
updatePayload.name = name;
|
|
||||||
}
|
|
||||||
if (description !== undefined) {
|
|
||||||
updatePayload.description = description;
|
|
||||||
updatePayload.notes = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updated = await this.prisma.modelType.update({
|
|
||||||
where: { id },
|
|
||||||
data: updatePayload,
|
|
||||||
include: {
|
|
||||||
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
|
||||||
pieceModels: true,
|
|
||||||
pieceRequirements: true,
|
|
||||||
pieces: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.mapModelTypePiece(updated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeTypePiece(id: string) {
|
findOneComposantModel(id: string) {
|
||||||
return this.prisma.modelType.delete({
|
return this.composantModelService.findOne(id);
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComposantModel methods
|
updateComposantModel(id: string, dto: UpdateComposantModelDto) {
|
||||||
async createComposantModel(createComposantModelDto: CreateComposantModelDto) {
|
return this.composantModelService.update(id, dto);
|
||||||
const { typeComposantId, ...data } = createComposantModelDto;
|
|
||||||
|
|
||||||
return this.prisma.composantModel.create({
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
typeComposant: {
|
|
||||||
connect: { id: typeComposantId },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllComposantModels(typeComposantId?: string) {
|
removeComposantModel(id: string) {
|
||||||
return this.prisma.composantModel.findMany({
|
return this.composantModelService.remove(id);
|
||||||
where: typeComposantId ? { typeComposantId } : undefined,
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
name: 'asc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneComposantModel(id: string) {
|
// PieceModel
|
||||||
return this.prisma.composantModel.findUnique({
|
createPieceModel(dto: CreatePieceModelDto) {
|
||||||
where: { id },
|
return this.pieceModelService.create(dto);
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateComposantModel(
|
findAllPieceModels(typePieceId?: string) {
|
||||||
id: string,
|
return this.pieceModelService.findAll(typePieceId);
|
||||||
updateComposantModelDto: UpdateComposantModelDto,
|
|
||||||
) {
|
|
||||||
const { typeComposantId, ...data } = updateComposantModelDto;
|
|
||||||
|
|
||||||
return this.prisma.composantModel.update({
|
|
||||||
where: { id },
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
...(typeComposantId
|
|
||||||
? {
|
|
||||||
typeComposant: {
|
|
||||||
connect: { id: typeComposantId },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
typeComposant: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeComposantModel(id: string) {
|
findOnePieceModel(id: string) {
|
||||||
return this.prisma.composantModel.delete({
|
return this.pieceModelService.findOne(id);
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PieceModel methods
|
updatePieceModel(id: string, dto: UpdatePieceModelDto) {
|
||||||
async createPieceModel(createPieceModelDto: CreatePieceModelDto) {
|
return this.pieceModelService.update(id, dto);
|
||||||
const { typePieceId, ...data } = createPieceModelDto;
|
|
||||||
|
|
||||||
return this.prisma.pieceModel.create({
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
typePiece: {
|
|
||||||
connect: { id: typePieceId },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllPieceModels(typePieceId?: string) {
|
removePieceModel(id: string) {
|
||||||
return this.prisma.pieceModel.findMany({
|
return this.pieceModelService.remove(id);
|
||||||
where: typePieceId ? { typePieceId } : undefined,
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
name: 'asc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOnePieceModel(id: string) {
|
|
||||||
return this.prisma.pieceModel.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async updatePieceModel(id: string, updatePieceModelDto: UpdatePieceModelDto) {
|
|
||||||
const { typePieceId, ...data } = updatePieceModelDto;
|
|
||||||
|
|
||||||
return this.prisma.pieceModel.update({
|
|
||||||
where: { id },
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
...(typePieceId
|
|
||||||
? {
|
|
||||||
typePiece: {
|
|
||||||
connect: { id: typePieceId },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
typePiece: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async removePieceModel(id: string) {
|
|
||||||
return this.prisma.pieceModel.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user