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 { TypesService } from './types.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', () => {
|
||||
let controller: TypesController;
|
||||
@@ -9,7 +18,19 @@ describe('TypesController', () => {
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [TypesController],
|
||||
providers: [TypesService, PrismaService],
|
||||
providers: [
|
||||
TypesService,
|
||||
TypeMachineService,
|
||||
TypeComponentService,
|
||||
TypePieceService,
|
||||
ComposantModelService,
|
||||
PieceModelService,
|
||||
TypeMachinesRepository,
|
||||
ModelTypesRepository,
|
||||
ComposantModelsRepository,
|
||||
PieceModelsRepository,
|
||||
PrismaService,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<TypesController>(TypesController);
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
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 { 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({
|
||||
controllers: [TypesController],
|
||||
providers: [TypesService],
|
||||
providers: [
|
||||
TypesService,
|
||||
TypeMachineService,
|
||||
TypeComponentService,
|
||||
TypePieceService,
|
||||
ComposantModelService,
|
||||
PieceModelService,
|
||||
TypeMachinesRepository,
|
||||
ModelTypesRepository,
|
||||
ComposantModelsRepository,
|
||||
PieceModelsRepository,
|
||||
],
|
||||
})
|
||||
export class TypesModule {}
|
||||
|
||||
@@ -1,13 +1,34 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TypesService } from './types.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', () => {
|
||||
let service: TypesService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [TypesService, PrismaService],
|
||||
providers: [
|
||||
TypesService,
|
||||
TypeMachineService,
|
||||
TypeComponentService,
|
||||
TypePieceService,
|
||||
ComposantModelService,
|
||||
PieceModelService,
|
||||
TypeMachinesRepository,
|
||||
ModelTypesRepository,
|
||||
ComposantModelsRepository,
|
||||
PieceModelsRepository,
|
||||
PrismaService,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<TypesService>(TypesService);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ModelCategory } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.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';
|
||||
import {
|
||||
CreateTypeMachineDto,
|
||||
UpdateTypeMachineDto,
|
||||
@@ -14,640 +17,118 @@ import {
|
||||
UpdatePieceModelDto,
|
||||
} from '../shared/dto/type.dto';
|
||||
|
||||
const CUSTOM_FIELD_SELECT = {
|
||||
id: true,
|
||||
name: true,
|
||||
type: true,
|
||||
required: true,
|
||||
options: true,
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
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 {
|
||||
return name
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.replace(/-+/g, '-');
|
||||
// TypeMachine
|
||||
createTypeMachine(dto: CreateTypeMachineDto) {
|
||||
return this.typeMachineService.create(dto);
|
||||
}
|
||||
|
||||
private async generateUniqueModelTypeCode(name: string): Promise<string> {
|
||||
const base = this.slugifyName(name) || 'type';
|
||||
let candidate = base;
|
||||
let suffix = 1;
|
||||
|
||||
while (
|
||||
await this.prisma.modelType.findUnique({
|
||||
where: { code: candidate },
|
||||
select: { id: true },
|
||||
})
|
||||
) {
|
||||
candidate = `${base}-${suffix++}`;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
findAllTypeMachines() {
|
||||
return this.typeMachineService.findAll();
|
||||
}
|
||||
|
||||
// TypeMachine methods
|
||||
async createTypeMachine(createTypeMachineDto: CreateTypeMachineDto) {
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
findOneTypeMachine(id: string) {
|
||||
return this.typeMachineService.findOne(id);
|
||||
}
|
||||
|
||||
async findAllTypeMachines() {
|
||||
return this.prisma.typeMachine.findMany({
|
||||
include: {
|
||||
machines: true,
|
||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
updateTypeMachine(id: string, dto: UpdateTypeMachineDto) {
|
||||
return this.typeMachineService.update(id, dto);
|
||||
}
|
||||
|
||||
async findOneTypeMachine(id: string) {
|
||||
return this.prisma.typeMachine.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
machines: true,
|
||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
removeTypeMachine(id: string) {
|
||||
return this.typeMachineService.remove(id);
|
||||
}
|
||||
|
||||
async updateTypeMachine(
|
||||
id: string,
|
||||
updateTypeMachineDto: UpdateTypeMachineDto,
|
||||
) {
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// TypeComposant
|
||||
createTypeComposant(dto: CreateTypeComposantDto) {
|
||||
return this.typeComponentService.create(dto);
|
||||
}
|
||||
|
||||
async removeTypeMachine(id: string) {
|
||||
// Vérifier s'il y a des machines liées à ce type
|
||||
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 },
|
||||
});
|
||||
findAllTypeComposants() {
|
||||
return this.typeComponentService.findAll();
|
||||
}
|
||||
|
||||
// TypeComposant methods (backed by ModelType with COMPONENT category)
|
||||
async createTypeComposant(createTypeComposantDto: CreateTypeComposantDto) {
|
||||
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 },
|
||||
},
|
||||
});
|
||||
findOneTypeComposant(id: string) {
|
||||
return this.typeComponentService.findOne(id);
|
||||
}
|
||||
|
||||
async findAllTypeComposants() {
|
||||
return this.prisma.modelType.findMany({
|
||||
where: { category: ModelCategory.COMPONENT },
|
||||
include: {
|
||||
composants: true,
|
||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||
models: true,
|
||||
},
|
||||
});
|
||||
updateTypeComposant(id: string, dto: UpdateTypeComposantDto) {
|
||||
return this.typeComponentService.update(id, dto);
|
||||
}
|
||||
|
||||
async findOneTypeComposant(id: string) {
|
||||
return this.prisma.modelType.findFirst({
|
||||
where: {
|
||||
id,
|
||||
category: ModelCategory.COMPONENT,
|
||||
},
|
||||
include: {
|
||||
composants: true,
|
||||
customFields: { select: CUSTOM_FIELD_SELECT },
|
||||
models: true,
|
||||
},
|
||||
});
|
||||
removeTypeComposant(id: string) {
|
||||
return this.typeComponentService.remove(id);
|
||||
}
|
||||
|
||||
async updateTypeComposant(
|
||||
id: string,
|
||||
updateTypeComposantDto: UpdateTypeComposantDto,
|
||||
) {
|
||||
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 },
|
||||
},
|
||||
});
|
||||
// TypePiece
|
||||
createTypePiece(dto: CreateTypePieceDto) {
|
||||
return this.typePieceService.create(dto);
|
||||
}
|
||||
|
||||
async removeTypeComposant(id: string) {
|
||||
return this.prisma.modelType.delete({
|
||||
where: { id },
|
||||
});
|
||||
findAllTypePieces() {
|
||||
return this.typePieceService.findAll();
|
||||
}
|
||||
|
||||
// TypePiece methods backed by ModelType
|
||||
private mapModelTypePiece(modelType: any) {
|
||||
if (!modelType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
pieceCustomFields,
|
||||
pieceModels,
|
||||
pieceRequirements,
|
||||
pieces,
|
||||
...rest
|
||||
} = modelType;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
customFields: pieceCustomFields ?? [],
|
||||
models: pieceModels ?? [],
|
||||
pieceRequirements: pieceRequirements ?? [],
|
||||
pieces: pieces ?? [],
|
||||
};
|
||||
findOneTypePiece(id: string) {
|
||||
return this.typePieceService.findOne(id);
|
||||
}
|
||||
|
||||
async createTypePiece(createTypePieceDto: CreateTypePieceDto) {
|
||||
const { customFields, description, name } = createTypePieceDto;
|
||||
|
||||
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);
|
||||
updateTypePiece(id: string, dto: UpdateTypePieceDto) {
|
||||
return this.typePieceService.update(id, dto);
|
||||
}
|
||||
|
||||
async findAllTypePieces() {
|
||||
const items = await this.prisma.modelType.findMany({
|
||||
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));
|
||||
removeTypePiece(id: string) {
|
||||
return this.typePieceService.remove(id);
|
||||
}
|
||||
|
||||
async findOneTypePiece(id: string) {
|
||||
const item = await this.prisma.modelType.findFirst({
|
||||
where: { id, category: ModelCategory.PIECE },
|
||||
include: {
|
||||
pieceCustomFields: { select: CUSTOM_FIELD_SELECT },
|
||||
pieceModels: true,
|
||||
pieceRequirements: true,
|
||||
pieces: true,
|
||||
},
|
||||
});
|
||||
|
||||
return this.mapModelTypePiece(item);
|
||||
// ComposantModel
|
||||
createComposantModel(dto: CreateComposantModelDto) {
|
||||
return this.composantModelService.create(dto);
|
||||
}
|
||||
|
||||
async updateTypePiece(id: string, updateTypePieceDto: UpdateTypePieceDto) {
|
||||
const { customFields, description, name } = updateTypePieceDto;
|
||||
|
||||
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);
|
||||
findAllComposantModels(typeComposantId?: string) {
|
||||
return this.composantModelService.findAll(typeComposantId);
|
||||
}
|
||||
|
||||
async removeTypePiece(id: string) {
|
||||
return this.prisma.modelType.delete({
|
||||
where: { id },
|
||||
});
|
||||
findOneComposantModel(id: string) {
|
||||
return this.composantModelService.findOne(id);
|
||||
}
|
||||
|
||||
// ComposantModel methods
|
||||
async createComposantModel(createComposantModelDto: CreateComposantModelDto) {
|
||||
const { typeComposantId, ...data } = createComposantModelDto;
|
||||
|
||||
return this.prisma.composantModel.create({
|
||||
data: {
|
||||
...data,
|
||||
typeComposant: {
|
||||
connect: { id: typeComposantId },
|
||||
},
|
||||
},
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
});
|
||||
updateComposantModel(id: string, dto: UpdateComposantModelDto) {
|
||||
return this.composantModelService.update(id, dto);
|
||||
}
|
||||
|
||||
async findAllComposantModels(typeComposantId?: string) {
|
||||
return this.prisma.composantModel.findMany({
|
||||
where: typeComposantId ? { typeComposantId } : undefined,
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc',
|
||||
},
|
||||
});
|
||||
removeComposantModel(id: string) {
|
||||
return this.composantModelService.remove(id);
|
||||
}
|
||||
|
||||
async findOneComposantModel(id: string) {
|
||||
return this.prisma.composantModel.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
});
|
||||
// PieceModel
|
||||
createPieceModel(dto: CreatePieceModelDto) {
|
||||
return this.pieceModelService.create(dto);
|
||||
}
|
||||
|
||||
async updateComposantModel(
|
||||
id: string,
|
||||
updateComposantModelDto: UpdateComposantModelDto,
|
||||
) {
|
||||
const { typeComposantId, ...data } = updateComposantModelDto;
|
||||
|
||||
return this.prisma.composantModel.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...data,
|
||||
...(typeComposantId
|
||||
? {
|
||||
typeComposant: {
|
||||
connect: { id: typeComposantId },
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
});
|
||||
findAllPieceModels(typePieceId?: string) {
|
||||
return this.pieceModelService.findAll(typePieceId);
|
||||
}
|
||||
|
||||
async removeComposantModel(id: string) {
|
||||
return this.prisma.composantModel.delete({
|
||||
where: { id },
|
||||
});
|
||||
findOnePieceModel(id: string) {
|
||||
return this.pieceModelService.findOne(id);
|
||||
}
|
||||
|
||||
// PieceModel methods
|
||||
async createPieceModel(createPieceModelDto: CreatePieceModelDto) {
|
||||
const { typePieceId, ...data } = createPieceModelDto;
|
||||
|
||||
return this.prisma.pieceModel.create({
|
||||
data: {
|
||||
...data,
|
||||
typePiece: {
|
||||
connect: { id: typePieceId },
|
||||
},
|
||||
},
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
});
|
||||
updatePieceModel(id: string, dto: UpdatePieceModelDto) {
|
||||
return this.pieceModelService.update(id, dto);
|
||||
}
|
||||
|
||||
async findAllPieceModels(typePieceId?: string) {
|
||||
return this.prisma.pieceModel.findMany({
|
||||
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 },
|
||||
});
|
||||
removePieceModel(id: string) {
|
||||
return this.pieceModelService.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user