diff --git a/mariadb/aria_log.00000001 b/mariadb/aria_log.00000001 index 63de30c..1e1098e 100644 Binary files a/mariadb/aria_log.00000001 and b/mariadb/aria_log.00000001 differ diff --git a/mariadb/aria_log_control b/mariadb/aria_log_control index 71edd37..7846535 100644 Binary files a/mariadb/aria_log_control and b/mariadb/aria_log_control differ diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 3572699..f86c5ae 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,27 +1,28 @@ -import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Patch, Post, UseGuards } from '@nestjs/common'; import { AuthService } from './auth.service'; import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto'; import { LoginDto } from './dto/login.dto'; - +import { AuthGuard } from '@nestjs/passport'; +import { UpdateUsuarioDto } from 'src/usuarios/dto/update-usuario.dto'; @Controller('auth') export class AuthController { - constructor( private readonly authService:AuthService){} - - @Post("registro") - registro(@Body() registroDto:CreateUsuarioDto ){ - return this.authService.registro(registroDto); - - } - - - @Post("login") - login(@Body() loginDto:LoginDto){ - return this.authService.login(loginDto); - } - - + constructor(private readonly authService: AuthService) {} + @UseGuards(AuthGuard('jwt')) + @Post('registro') + registro(@Body() registroDto: CreateUsuarioDto) { + return this.authService.registro(registroDto); + } + @UseGuards(AuthGuard('jwt')) + @Patch('update') + update(@Body() registroDto: UpdateUsuarioDto) { + return this.authService.update(registroDto); + } + @Post('login') + login(@Body() loginDto: LoginDto) { + return this.authService.login(loginDto); + } } diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index bac9631..c5eb8b9 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -9,6 +9,7 @@ import * as bcrypt from 'bcryptjs'; import { LoginDto } from './dto/login.dto'; import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto'; import { JwtService } from '@nestjs/jwt'; +import { UpdateUsuarioDto } from 'src/usuarios/dto/update-usuario.dto'; @Injectable() export class AuthService { @@ -17,6 +18,18 @@ export class AuthService { private readonly jwtService: JwtService, ) {} + async update(registroDto: UpdateUsuarioDto) { + const update_data = await this.usuarioService.actualizarUsuario( + registroDto.id_User, + { + nombre: registroDto.nombre, + contraseña: registroDto.contraseña, + id_tipo_usuario: registroDto.tipoUsuario, + }, + ); + return update_data; + } + async registro({ nombre, contraseña, tipoUsuario }: CreateUsuarioDto) { const usuario = await this.usuarioService.findOneByName(nombre); if (usuario) { diff --git a/src/equipo/equipo.controller.ts b/src/equipo/equipo.controller.ts index d8af52a..8bda817 100644 --- a/src/equipo/equipo.controller.ts +++ b/src/equipo/equipo.controller.ts @@ -351,15 +351,20 @@ let tabletas = ['TABLETA ANDROID', 'TABLETA iPAD OS']; let impresoras = [ 'INYECCIÓN TINTA', 'LÁSER DE ALTO VOLUMEN B/N', + 'LÁSER DE ALTO VOLUMEN COLOR', 'LÁSER PEQUEÑA B/N', 'LÁSER PEQUEÑA COLOR', 'MATRIZ DE PUNTOS', 'MULTIFUNCIONALES', - '3D', + 'IMPRESORA TÉRMICA', + 'IMPRESORA CREDENCIALES', + 'PLOTTER', ]; let dijitales = [ + '3D', 'DIGITALIZADOR DE CAMA PLANA PARA OFICINA', + 'DIGITALIZADOR DE GRAN VOLUMEN', 'DIGITALIZADOR CON ALIMENTADOR DE HOJAS PARA OFICINA', ]; diff --git a/src/equipo/equipo.service.ts b/src/equipo/equipo.service.ts index 39eb02a..bec158b 100644 --- a/src/equipo/equipo.service.ts +++ b/src/equipo/equipo.service.ts @@ -359,11 +359,52 @@ export class EquipoService { } async createEcxel(res: Response) { - let obj = await this.generar_reporte(); - const objectParse = Array.isArray(obj) - ? obj.map((item) => this.flattenObject(item)) - : [this.flattenObject(obj)]; - return this.exportToClient(objectParse, res); + const data = await this.generar_reporte(); + return this.exportarReporteAExcel(data, res); + } + + async exportarReporteAExcel(data: any, res: Response) { + const workbook = new ExcelJS.Workbook(); + + for (const key of Object.keys(data)) { + const sheetName = key.substring(0, 30); // Excel limita a 30 caracteres + const sheet = workbook.addWorksheet(sheetName); + + const rows = data[key]; + + if (!Array.isArray(rows) || rows.length === 0) { + sheet.addRow([`(sin datos)`]); + continue; + } + + // Obtener columnas automáticamente + const headers = Object.keys(rows[0]); + + // Crear encabezado + sheet.addRow(headers); + + // Agregar filas + for (const row of rows) { + sheet.addRow(headers.map((h) => row[h])); + } + + // Estilo básico + sheet.getRow(1).font = { bold: true }; + sheet.getRow(1).alignment = { horizontal: 'center' }; + sheet.columns.forEach((col) => { + col.width = 35; + }); + } + + // Enviar el archivo al cliente + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + ); + res.setHeader('Content-Disposition', 'attachment; filename=reporte.xlsx'); + + await workbook.xlsx.write(res); + res.end(); } async createReport() { @@ -441,10 +482,8 @@ export class EquipoService { .createQueryBuilder('e') .innerJoin('e.tipoEquipo', 't') .where('t.tipo_equipo IN (:...tipo_equipo)', { tipo_equipo }) - .select(['t.tipo_equipo AS tipo_equipo']) - .addSelect('COUNT(*) AS total') - .groupBy('t.tipo_equipo') - .getRawMany(); + .select('COUNT(*) AS total') + .getRawOne(); return count; } catch (error) { @@ -489,27 +528,21 @@ export class EquipoService { .groupBy('e.antiguedad') .getRawMany(); - interface Porcentaje { - antiguedad: any; - total: any; - porcentaje: string; - } - return { escritorios: countEscritorios.map((i) => ({ antiguedad: i.antiguedad, total: i.total, - porcentaje: ((i.total / totalEscrtitorio) * 100).toFixed(2), + porcentaje: ((i.total / totalEscrtitorio.total) * 100).toFixed(2), })), portatiles: countPortatiles.map((i) => ({ antiguedad: i.antiguedad, total: i.total, - porcentaje: ((i.total / totalPortatiles) * 100).toFixed(2), + porcentaje: ((i.total / totalPortatiles.total) * 100).toFixed(2), })), altoRendimiento: countAltoRendimiento.map((i) => ({ antiguedad: i.antiguedad, total: i.total, - porcentaje: ((i.total / totalAltoRendimiento) * 100).toFixed(2), + porcentaje: ((i.total / totalAltoRendimiento.total) * 100).toFixed(2), })), }; } catch (error) { @@ -596,20 +629,25 @@ export class EquipoService { }> { try { // Helper para obtener total por tipos de equipo (count simple, sin group by) - const getTotalPorTipos = async (tipos: string[]): Promise => { + const getTotalPorTipos = async (tipos: string[]): Promise => { if (!tipos || tipos.length === 0) return 0; return this.equipoRepository .createQueryBuilder('e') - .innerJoin('e.tipoEquipo', 't') - .where('t.tipo_equipo IN (:...tipos)', { tipos }) - .getCount(); + .innerJoin('e.periferico', 'p') + .where('p.periferico IN (:...tipos)', { tipos }) + .select('COUNT(*) AS total') + .getRawOne(); }; // Ejecutar ambos totales en paralelo - const [totalImpresion, totalDigitalizacion] = await Promise.all([ + + const [totalI, totalD] = await Promise.all([ getTotalPorTipos(impresion), getTotalPorTipos(digitalizacion), ]); + const totalImpresion = totalI.total; + + const totalDigitalizacion = totalD.total; // Obtener conteos por antiguedad para impresion const countImpresionPromise = this.equipoRepository @@ -641,6 +679,11 @@ export class EquipoService { countDigitalizacionPromise, ]); + console.log('I', totalImpresion); + console.log('D', totalDigitalizacion); + console.log('I', countImpresion); + console.log('D', countDigitalizacion); + // Tipo para salida interface Porcentaje { antiguedad: any; diff --git a/src/usuarios/dto/update-usuario.dto.ts b/src/usuarios/dto/update-usuario.dto.ts index a2b8fbc..56453fa 100644 --- a/src/usuarios/dto/update-usuario.dto.ts +++ b/src/usuarios/dto/update-usuario.dto.ts @@ -1,4 +1,29 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateUsuarioDto } from './create-usuario.dto'; +import { DefaultValuePipe } from '@nestjs/common'; +import { Transform } from 'class-transformer'; +import { + IsInt, + IsNotEmpty, + IsOptional, + IsString, + MinLength, +} from 'class-validator'; -export class UpdateUsuarioDto extends PartialType(CreateUsuarioDto) {} +export class UpdateUsuarioDto { + @IsString() + @IsNotEmpty() + id_User: number; + + @IsString() + @IsOptional() + nombre?: string; + + @IsString() + @MinLength(5) + @Transform(({ value }) => value.trim()) + @IsOptional() + contraseña?: string; + + @IsInt() + @IsOptional() + tipoUsuario?: number; +} diff --git a/src/usuarios/usuarios.service.ts b/src/usuarios/usuarios.service.ts index 2465391..105c35b 100644 --- a/src/usuarios/usuarios.service.ts +++ b/src/usuarios/usuarios.service.ts @@ -1,8 +1,13 @@ -import { Injectable } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; import { CreateUsuarioDto } from './dto/create-usuario.dto'; import { InjectRepository } from '@nestjs/typeorm'; import { Tipo_Usuario, Usuario } from './entities/usuario.entity'; import { Repository } from 'typeorm'; +import * as bcrypt from 'bcryptjs'; @Injectable() export class UsuariosService { @@ -13,6 +18,49 @@ export class UsuariosService { @InjectRepository(Tipo_Usuario) private readonly tipoUsuarioRepository: Repository, ) {} + + async actualizarUsuario( + id: number, + datos: { nombre?: string; contraseña?: string; id_tipo_usuario?: number }, + ) { + // Buscar al usuario + const usuario = await this.usuarioRepository.findOne({ + where: { id_usuario: id }, + relations: ['tipoUsuario'], + }); + + if (!usuario) { + throw new NotFoundException('Usuario no encontrado'); + } + + // Actualizar nombre + if (datos.nombre) { + usuario.nombre = datos.nombre; + } + + // Actualizar contraseña con hash + if (datos.contraseña) { + const hashed = await bcrypt.hash(datos.contraseña, 10); + usuario.contraseña = hashed; + } + + // Actualizar tipo de usuario + if (datos.id_tipo_usuario) { + const tipo = await this.tipoUsuarioRepository.findOne({ + where: { id_tipo_usuario: datos.id_tipo_usuario }, + }); + + if (!tipo) { + throw new BadRequestException('El tipo de usuario no existe'); + } + + usuario.tipoUsuario = tipo; + } + + // Guardar cambios + return await this.usuarioRepository.save(usuario); + } + async create(createUsuarioDto: CreateUsuarioDto) { let user = await this.usuarioRepository.create({ nombre: createUsuarioDto.nombre,