import { Injectable, NotFoundException } from '@nestjs/common'; import type { Prisma } from '@prisma/client'; import type { Response } from 'express'; import { PrismaService } from '../../prisma/prisma.service'; import { getFirst, setListHeaders, toArray, toDateValue, toDecimalValue, toNumberValue } from '../shared/query-utils'; import { CreateEmployeeDto } from './dto/create-employee.dto'; import { UpdateEmployeeDto } from './dto/update-employee.dto'; @Injectable() export class EmployeeService { constructor(private readonly prisma: PrismaService) {} private toNested(item: any): Record { return { id: item.code, code: item.code, fullName: item.fullName, role: item.role, position: item.position, bossCode: item.bossCode, price: item.price, phoneNumber: item.phoneNumber, }; } private toRecord(item: any): Record { return { id: item.code, code: item.code, fullName: item.fullName, role: item.role, position: item.position, bossCode: item.bossCode, boss: item.boss ? this.toNested(item.boss) : null, subordinates: Array.isArray(item.subordinates) ? item.subordinates.map((subordinate: any) => this.toNested(subordinate)) : [], price: item.price, phoneNumber: item.phoneNumber, }; } async findAll(query: Record, response: Response): Promise[]> { const start = Number(getFirst(query._start) ?? 0); const end = Number(getFirst(query._end) ?? start + 25); const take = Math.max(end - start, 0) || 25; const where: Record = {}; const q = getFirst(query.q); if (q) { where.OR = [ { code: { contains: q, mode: 'insensitive' } }, { fullName: { contains: q, mode: 'insensitive' } }, { position: { contains: q, mode: 'insensitive' } }, ]; } const code = getFirst(query.code); if (code) where.code = { contains: code, mode: 'insensitive' }; const fullName = getFirst(query.fullName); if (fullName) where.fullName = { contains: fullName, mode: 'insensitive' }; const position = getFirst(query.position); if (position) where.position = { contains: position, mode: 'insensitive' }; const roleValues = toArray(query.role); if (roleValues.length > 0) where.role = { in: Array.from(new Set(roleValues)) }; const boss = getFirst(query.boss); if (boss) where.bossCode = boss; const sortField = getFirst(query._sort) ?? 'code'; const prismaSortField = sortField === 'id' ? 'code' : sortField; const sortOrder = (String(getFirst(query._order) ?? 'ASC').toLowerCase() === 'desc' ? 'desc' : 'asc') as Prisma.SortOrder; const [items, total] = await this.prisma.$transaction([ this.prisma.employee.findMany({ where, skip: start, take, orderBy: { [prismaSortField]: sortOrder }, include: { boss: true, subordinates: true, }, }), this.prisma.employee.count({ where }), ]); setListHeaders(response, total, start, end, 'employees'); return items.map((item) => this.toRecord(item)); } async findOne(code: string): Promise> { const item = await this.prisma.employee.findUnique({ where: { code }, include: { boss: true, subordinates: true, }, }); if (!item) throw new NotFoundException('Employee not found'); return this.toRecord(item); } async create(dto: CreateEmployeeDto): Promise> { const created = await this.prisma.employee.create({ data: this.prepareCreateData(dto) as any, include: { boss: true, subordinates: true, }, }); return this.toRecord(created); } async update(code: string, dto: UpdateEmployeeDto): Promise> { const updated = await this.prisma.employee.update({ where: { code }, data: this.prepareUpdateData(dto) as any, include: { boss: true, subordinates: true, }, }); return this.toRecord(updated); } async remove(code: string): Promise> { const deleted = await this.prisma.employee.delete({ where: { code }, include: { boss: true, subordinates: true, }, }); return this.toRecord(deleted); } private prepareCreateData(dto: CreateEmployeeDto): Record { return { code: dto.code, fullName: dto.fullName, role: dto.role, position: dto.position, bossCode: dto.boss ?? null, price: toNumberValue(dto.price), phoneNumber: toNumberValue(dto.phoneNumber), }; } private prepareUpdateData(dto: UpdateEmployeeDto): Record { const { id, code: _pk, ...rest } = dto as Record & { id?: string; code?: string }; return { fullName: rest.fullName, role: rest.role, position: rest.position, bossCode: rest.boss ?? null, price: toNumberValue(rest.price), phoneNumber: toNumberValue(rest.phoneNumber), }; } }