cambio de inf en los reportes

This commit is contained in:
2025-11-21 11:51:30 -06:00
parent 3472aa911d
commit 9d513c3439
8 changed files with 180 additions and 45 deletions
Binary file not shown.
Binary file not shown.
+18 -17
View File
@@ -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);
}
}
+13
View File
@@ -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) {
+6 -1
View File
@@ -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',
];
+66 -23
View File
@@ -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<number> => {
const getTotalPorTipos = async (tipos: string[]): Promise<any> => {
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;
+28 -3
View File
@@ -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;
}
+49 -1
View File
@@ -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<Tipo_Usuario>,
) {}
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,