import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { CreateEmployeeDto } from '../dtos/create-employee.dto'; import { UpdateEmployeeDto } from '../dtos/update-employee.dto'; import { Employees, Users } from '@prisma/client'; @Injectable() export class EmployeesService { constructor(private readonly prisma: PrismaService) {} async create(dto: CreateEmployeeDto): Promise { const { first_name, last_name, email, phone_number, residence, external_payroll_id, company_code, first_work_day, last_work_day, } = dto; return this.prisma.$transaction(async (tx) => { const user: Users = await tx.users.create({ data: { first_name, last_name, email, phone_number, residence, }, }); return tx.employees.create({ data: { user_id: user.id, external_payroll_id, company_code, first_work_day, last_work_day, }, }); }); } findAll(): Promise { return this.prisma.employees.findMany({ include: { user: true }, }); } async findOne(id: number): Promise { const emp = await this.prisma.employees.findUnique({ where: { id }, include: { user: true }, }); if (!emp) { throw new NotFoundException(`Employee #${id} not found`); } return emp; } async update( id: number, dto: UpdateEmployeeDto, ): Promise { const emp = await this.findOne(id); const { first_name, last_name, email, phone_number, residence, external_payroll_id, company_code, first_work_day, last_work_day, } = dto; return this.prisma.$transaction(async (tx) => { await tx.users.update({ where: { id: emp.user_id }, data: { ...(first_name !== undefined && { first_name }), ...(last_name !== undefined && { last_name }), ...(email !== undefined && { email }), ...(phone_number !== undefined && { phone_number }), ...(residence !== undefined && { residence }), }, }); return tx.employees.update({ where: { id }, data: { ...(external_payroll_id !== undefined && { external_payroll_id }), ...(company_code !== undefined && { company_code }), ...(first_work_day !== undefined && { first_work_day }), ...(last_work_day !== undefined && { last_work_day }), }, }); }); } async remove(id: number): Promise { await this.findOne(id); return this.prisma.employees.delete({ where: { id } }); } //archivation function async patchEmployee(id: number, dto: UpdateEmployeeDto): Promise { //fetching existing employee const existing = await this.prisma.employees.findUnique({ where: { id }, include: { user: true, archive: true }, }); if (existing) { //verify last_work_day is not null => trigger archivation if(dto.last_work_day != undefined && existing.last_work_day == null) { return this.archiveOnTermination(existing, dto); } //if null => regular update return this.prisma.employees.update({ where: { id }, data: dto, }); } //if not found => fetch archives side for restoration const archived = await this.prisma.employeesArchive.findFirst({ where: { employee_id: id }, include: { employee: true, user: true }, }); if (archived) { //conditions for restoration const restore = dto.last_work_day === null || dto.first_work_day != null; if(restore) { return this.restoreEmployee(archived, dto); } } //if neither activated nor archivated => 404 return null; } //transfers the employee to archive and then delete from employees table private async archiveOnTermination(existing: any, dto: UpdateEmployeeDto): Promise { return this.prisma.$transaction(async transaction => { //archive insertion const archived = await transaction.employeesArchive.create({ data: { employee_id: existing.id, user_id: existing.user_id, first_name: existing.first_name, last_name: existing.last_name, external_payroll_id: existing.external_payroll_id, company_code: existing.company_code, first_Work_Day: existing.first_Work_Day, last_work_day: existing.last_work_day, supervisor_id: existing.supervisor_id ?? null, }, }); //delete from employees table await transaction.employees.delete({ where: { id: existing.id } }); //return archived employee return archived }); } //transfers the employee from archive to the employees table private async restoreEmployee(archived: any, dto: UpdateEmployeeDto): Promise { return this.prisma.$transaction(async transaction => { //restores the archived employee into the employees table const restored = await transaction.employees.create({ data: { id: archived.employee_id, user_id: archived.user_id, external_payroll_id: dto.external_payroll_id ?? archived.external_payroll_id, company_code: dto.company_code ?? archived.company_code, first_work_day: dto.first_work_day ?? archived.first_Work_Day, last_work_day: null, supervisor_id: dto.supervisor_id ?? archived.supervisor_id, }, }); //deleting archived entry by id await transaction.employeesArchive.delete({ where: { id: archived.id } }); //return restored employee return restored; }); } }