863 lines
25 KiB
TypeScript
863 lines
25 KiB
TypeScript
import {
|
|
BadRequestException,
|
|
Injectable,
|
|
NotFoundException,
|
|
} from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { Equipo } from './entities/equipo.entity';
|
|
import { UpdateEquipoDto } from './dto/update-equipo.dto';
|
|
import axios from 'axios';
|
|
import e, { Response } from 'express';
|
|
import * as ExcelJS from 'exceljs';
|
|
import {
|
|
Adscripcion,
|
|
Estado,
|
|
Marca,
|
|
Periferico,
|
|
Procesador,
|
|
SistemaOperativo,
|
|
TipoEquipo,
|
|
Uso,
|
|
} from './entities/catalogo.entities';
|
|
|
|
import { CreateEquipoDto } from './dto/create-equipo.dto';
|
|
|
|
import { MovimientoService } from 'src/movimiento/movimiento.service';
|
|
|
|
@Injectable()
|
|
export class EquipoService {
|
|
constructor(
|
|
private readonly movimiento: MovimientoService,
|
|
|
|
@InjectRepository(Equipo)
|
|
private readonly equipoRepository: Repository<Equipo>,
|
|
@InjectRepository(Uso)
|
|
private readonly usoRepo: Repository<Uso>,
|
|
|
|
@InjectRepository(Marca)
|
|
private readonly marcaRepo: Repository<Marca>,
|
|
|
|
@InjectRepository(Estado)
|
|
private readonly estadoRepo: Repository<Estado>,
|
|
|
|
@InjectRepository(Adscripcion)
|
|
private readonly adscripcionRepo: Repository<Adscripcion>,
|
|
|
|
@InjectRepository(TipoEquipo)
|
|
private readonly tipoEquipoRepo: Repository<TipoEquipo>,
|
|
|
|
@InjectRepository(SistemaOperativo)
|
|
private readonly sistemaOperativoRepo: Repository<SistemaOperativo>,
|
|
|
|
@InjectRepository(Procesador)
|
|
private readonly procesadorRepo: Repository<Procesador>,
|
|
|
|
@InjectRepository(Periferico)
|
|
private readonly perifericoRepo: Repository<Periferico>,
|
|
) {}
|
|
|
|
async deleteEquipo(inventario: string): Promise<{ message: string }> {
|
|
const equipo = await this.equipoRepository.findOne({
|
|
where: { inventario },
|
|
});
|
|
|
|
if (!equipo) {
|
|
throw new NotFoundException(
|
|
`No se encontró el equipo con id ${inventario}`,
|
|
);
|
|
}
|
|
|
|
await this.equipoRepository.remove(equipo);
|
|
|
|
return {
|
|
message: `Equipo con inv ${inventario} eliminado correctamente`,
|
|
};
|
|
}
|
|
|
|
async buscarEquipos(filtros: any, page: number = 1, limit: number = 10) {
|
|
const query = this.equipoRepository
|
|
.createQueryBuilder('equipo')
|
|
.leftJoinAndSelect('equipo.marca', 'marca')
|
|
.leftJoinAndSelect('equipo.estado', 'estado')
|
|
.leftJoinAndSelect('equipo.adscripcion', 'adscripcion')
|
|
.leftJoinAndSelect('equipo.tipoEquipo', 'tipoEquipo')
|
|
.leftJoinAndSelect('equipo.sistemaOperativo', 'sistemaOperativo')
|
|
.leftJoinAndSelect('equipo.procesador', 'procesador')
|
|
.leftJoinAndSelect('equipo.tipoUso', 'tipoUso');
|
|
|
|
// Filtros dinámicos
|
|
if (filtros.inventario) {
|
|
query.andWhere('equipo.inventario LIKE :inventario', {
|
|
inventario: `%${filtros.inventario}%`,
|
|
});
|
|
}
|
|
|
|
if (filtros.tipoEquipo) {
|
|
query.andWhere('tipoEquipo.id = :tipoEquipo', {
|
|
tipoEquipo: filtros.tipoEquipo,
|
|
});
|
|
}
|
|
|
|
if (filtros.antiguedad) {
|
|
query.andWhere('equipo.antiguedad LIKE :antiguedad', {
|
|
antiguedad: `%${filtros.antiguedad}%`,
|
|
});
|
|
}
|
|
|
|
if (filtros.marca) {
|
|
query.andWhere('marca.id = :marca', { marca: filtros.marca });
|
|
}
|
|
|
|
if (filtros.estado) {
|
|
query.andWhere('estado.id = :estado', { estado: filtros.estado });
|
|
}
|
|
|
|
if (filtros.adscripcion) {
|
|
query.andWhere('adscripcion.id = :adscripcion', {
|
|
adscripcion: filtros.adscripcion,
|
|
});
|
|
}
|
|
|
|
if (filtros.tipoUso) {
|
|
query.andWhere('tipoUso.id = :tipoUso', { tipoUso: filtros.tipoUso });
|
|
}
|
|
|
|
if (filtros.procesador) {
|
|
query.andWhere('procesador.id = :procesador', {
|
|
procesador: filtros.procesador,
|
|
});
|
|
}
|
|
|
|
if (filtros.sistemaOperativo) {
|
|
query.andWhere('sistemaOperativo.id = :sistemaOperativo', {
|
|
sistemaOperativo: filtros.sistemaOperativo,
|
|
});
|
|
}
|
|
|
|
// Paginación
|
|
query.skip((page - 1) * limit).take(limit);
|
|
|
|
// Ejecutar consulta
|
|
const [data, total] = await query.getManyAndCount();
|
|
|
|
return {
|
|
total,
|
|
page,
|
|
limit,
|
|
data,
|
|
};
|
|
}
|
|
async updateEquipo(equipoNuevo: UpdateEquipoDto, id_equipo: number, id_user) {
|
|
let equipo = await this.equipoRepository.findOne({
|
|
where: { id_equipo },
|
|
relations: ['tipoEquipo'],
|
|
});
|
|
if (!equipo) {
|
|
throw new NotFoundException('No se encontó equipo');
|
|
}
|
|
|
|
const updateData = {
|
|
id_equipo,
|
|
lugar: equipoNuevo.lugar ? equipoNuevo.lugar : undefined,
|
|
serie: equipoNuevo.serie ? equipoNuevo.serie : undefined,
|
|
modelo: equipoNuevo.modelo ? equipoNuevo.modelo : undefined,
|
|
estado: equipoNuevo.id_estado
|
|
? { id_estado: equipoNuevo.id_estado }
|
|
: undefined,
|
|
adscripcion: equipoNuevo.id_adscripcion
|
|
? { id_adscripcion: equipoNuevo.id_adscripcion }
|
|
: undefined,
|
|
sistemaOperativo: equipoNuevo.id_sistema_operativo
|
|
? { id_sistema_operativo: equipoNuevo.id_sistema_operativo }
|
|
: undefined,
|
|
procesador: equipoNuevo.id_procesador
|
|
? { id_procesador: equipoNuevo.id_procesador }
|
|
: undefined,
|
|
tipoUso: equipoNuevo.id_tipo_uso
|
|
? { id_uso: equipoNuevo.id_tipo_uso }
|
|
: undefined,
|
|
marca: equipoNuevo.id_marca
|
|
? { id_marca: equipoNuevo.id_marca }
|
|
: undefined,
|
|
periferico: equipoNuevo.id_periferico
|
|
? { id_periferico: equipoNuevo.id_periferico }
|
|
: undefined,
|
|
};
|
|
|
|
console.log(updateData);
|
|
const equipoUpdate = await this.equipoRepository.preload(updateData);
|
|
console.log(equipoNuevo);
|
|
if (!equipoUpdate) {
|
|
throw new Error(`No se encontró el equipo con id ${id_equipo}`);
|
|
}
|
|
const mov = await this.movimiento.crear({
|
|
idUsuario: id_user,
|
|
idEquipo: id_equipo,
|
|
observaciones: equipoNuevo.observaciones,
|
|
});
|
|
return await this.equipoRepository.save(equipoUpdate);
|
|
}
|
|
|
|
async findEquipo(inventario: string) {
|
|
const equipo = await this.equipoRepository.findOne({
|
|
where: { inventario },
|
|
relations: [
|
|
'marca',
|
|
'estado',
|
|
'adscripcion',
|
|
'tipoEquipo',
|
|
'sistemaOperativo',
|
|
'procesador',
|
|
'tipoUso',
|
|
'periferico',
|
|
],
|
|
});
|
|
|
|
if (!equipo) {
|
|
throw new NotFoundException(
|
|
`No se encontró el equipo con inventario ${inventario}`,
|
|
);
|
|
}
|
|
|
|
const responsable = await this.searchResponsable(
|
|
equipo.adscripcion.adscripcion,
|
|
);
|
|
|
|
const observaciones = await this.movimiento.buscar(equipo.id_equipo);
|
|
|
|
return { ...equipo, ...responsable, ...observaciones };
|
|
}
|
|
|
|
async searchResponsable(nombreAdscripcion: string) {
|
|
const adscripcion = await this.adscripcionRepo.findOneBy({
|
|
adscripcion: nombreAdscripcion,
|
|
});
|
|
if (!adscripcion) {
|
|
throw new Error(
|
|
`No se encontró la adscripción con nombre ${nombreAdscripcion}`,
|
|
);
|
|
}
|
|
let entrada = {
|
|
tipoBusqueda: 'area',
|
|
IdUnidadResponsable: adscripcion.id_adscripcion,
|
|
};
|
|
|
|
const url = process.env.API_FUNCIONARIOS;
|
|
|
|
if (!url) throw new Error('Url no definida en las variables de entorno');
|
|
console.log(entrada);
|
|
const response = await axios.post(url, entrada);
|
|
return response.data;
|
|
}
|
|
|
|
async create(equipo: CreateEquipoDto, id_usuario: number) {
|
|
const equipoExistente = await this.equipoRepository.findOne({
|
|
where: { inventario: equipo.inventario },
|
|
});
|
|
if (equipoExistente) {
|
|
throw new BadRequestException('El equipo ya existe');
|
|
}
|
|
|
|
const datosBase = {
|
|
inventario: equipo.inventario,
|
|
serie: equipo.serie,
|
|
lugar: equipo.lugar,
|
|
fechaFactura: equipo.fechaFactura,
|
|
antiguedad: equipo.antiguedad,
|
|
modelo: equipo.modelo,
|
|
estado: { id_estado: equipo.id_estado },
|
|
adscripcion: { id_adscripcion: equipo.id_adscripcion },
|
|
tipoUso: { id_uso: equipo.id_uso },
|
|
marca: { id_marca: equipo.id_marca },
|
|
tipoEquipo: { id_tipo_de_equipo: equipo.id_tipo_equipo },
|
|
};
|
|
|
|
const nuevoEquipo = this.equipoRepository.create(
|
|
equipo.isImpresora
|
|
? { ...datosBase, periferico: { id_periferico: equipo.id_periferico } }
|
|
: {
|
|
...datosBase,
|
|
sistemaOperativo: {
|
|
id_sistema_operativo: equipo.id_sistema_operativo,
|
|
},
|
|
procesador: { id_procesador: equipo.id_procesador },
|
|
},
|
|
);
|
|
|
|
let equip = await this.equipoRepository.save(nuevoEquipo);
|
|
|
|
if (!equip) throw new Error('No se creó el equipo');
|
|
|
|
// Crear movimiento asociado
|
|
await this.movimiento.crear({
|
|
idEquipo: equip.id_equipo,
|
|
idUsuario: id_usuario,
|
|
});
|
|
|
|
return equip;
|
|
}
|
|
|
|
async findAllUsos() {
|
|
return await this.usoRepo.find();
|
|
}
|
|
|
|
async findAllMarcas() {
|
|
return await this.marcaRepo.find();
|
|
}
|
|
|
|
async findAllEstados() {
|
|
return await this.estadoRepo.find();
|
|
}
|
|
|
|
async findAllAdscripciones() {
|
|
return await this.adscripcionRepo.find();
|
|
}
|
|
|
|
async findAllTiposEquipo() {
|
|
return await this.tipoEquipoRepo.find();
|
|
}
|
|
|
|
async findAllSistemasOperativos() {
|
|
return await this.sistemaOperativoRepo.find();
|
|
}
|
|
|
|
async findAllProcesadores() {
|
|
return await this.procesadorRepo.find();
|
|
}
|
|
|
|
async findAllPerifericos() {
|
|
return await this.perifericoRepo.find();
|
|
}
|
|
|
|
async findAllProcesadorTipoEquipos() {
|
|
return await this.procesadorRepo.find();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
async createReport() {
|
|
let obj = await this.generar_reporte();
|
|
const objectParse = Array.isArray(obj)
|
|
? obj.map((item) => this.flattenObject(item))
|
|
: [this.flattenObject(obj)];
|
|
return objectParse;
|
|
}
|
|
|
|
async contar_tipoEquipos_tipoUso(): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't') // une la tabla usuario
|
|
.innerJoin('e.tipoUso', 'u') // une la tabla categoria
|
|
.select(['u.tipo_uso AS uso', 't.tipo_equipo AS categoria'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('t.id_tipo_de_equipo')
|
|
.addGroupBy('u.id_uso')
|
|
.getRawMany();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_tipoEquipos_sistemasOperativos(
|
|
tipo_equipo: string[],
|
|
): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.innerJoin('e.sistemaOperativo', 's')
|
|
.where('t.tipo_equipo IN (:...tipo_equipo)', { tipo_equipo })
|
|
.select(['s.sistema_operativo AS sistema_operativo'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('s.sistema_operativo')
|
|
.getRawMany();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_tipoEquipos_procesador(tipo_equipo: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.procesador', 'p')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('t.tipo_equipo IN (:...tipo_equipo)', { tipo_equipo })
|
|
.select(['p.procesador AS procesador'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('p.procesador')
|
|
.getRawMany();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_tipoEquipos(tipo_equipo: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.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();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_tipoEquipos_antiguedad(): Promise<any> {
|
|
const totalEscrtitorio = this.contar_tipoEquipos([
|
|
'ESCRITORIO PC',
|
|
'ESCRITORIO MAC OS',
|
|
'ESCRITORIO LINUX',
|
|
]);
|
|
const totalPortatiles = this.contar_tipoEquipos([
|
|
'PORTÁTILES WINDOWS',
|
|
'PORTÁTILES CHROMEBOOK',
|
|
'PORTÁTILES MAC OS',
|
|
]);
|
|
const totalAltoRendimiento = this.contar_tipoEquipos(['SERVIDOR']);
|
|
try {
|
|
const countEscritorios = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('t.tipo_equipo IN (:...tipo_equipo)', {
|
|
tipo_equipo: [
|
|
'ESCRITORIO PC',
|
|
'ESCRITORIO MAC OS',
|
|
'ESCRITORIO LINUX',
|
|
],
|
|
})
|
|
.select(['e.antiguedad AS antiguedad'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('e.antiguedad')
|
|
.getRawMany();
|
|
const countPortatiles = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('t.tipo_equipo IN (:...tipo_equipo)', {
|
|
tipo_equipo: [
|
|
'PORTÁTILES WINDOWS',
|
|
'PORTÁTILES CHROMEBOOK',
|
|
'PORTÁTILES MAC OS',
|
|
],
|
|
})
|
|
.select(['e.antiguedad AS antiguedad'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('e.antiguedad')
|
|
.getRawMany();
|
|
const countAltoRendimiento = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('t.tipo_equipo IN (:...tipo_equipo)', {
|
|
tipo_equipo: ['SERVIDOR'],
|
|
})
|
|
.select(['e.antiguedad AS antiguedad'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('e.antiguedad')
|
|
.getRawMany();
|
|
|
|
interface Porcentaje {
|
|
antiguedad: any;
|
|
total: any;
|
|
porcentaje: string;
|
|
}
|
|
|
|
let porcentajesEscritorios: Porcentaje[] = [];
|
|
let porcentajesPortatiles: Porcentaje[] = [];
|
|
let porcentajesAltoRendimiento: Porcentaje[] = [];
|
|
|
|
countEscritorios.forEach(async (item) => {
|
|
porcentajesEscritorios.push({
|
|
antiguedad: item.antiguedad,
|
|
total: item.total,
|
|
porcentaje: ((item.total / (await totalEscrtitorio)) * 100).toFixed(
|
|
2,
|
|
),
|
|
});
|
|
});
|
|
|
|
countPortatiles.forEach(async (item) => {
|
|
porcentajesPortatiles.push({
|
|
antiguedad: item.antiguedad,
|
|
total: item.total,
|
|
porcentaje: ((item.total / (await totalPortatiles)) * 100).toFixed(2),
|
|
});
|
|
});
|
|
|
|
countAltoRendimiento.forEach(async (item) => {
|
|
porcentajesAltoRendimiento.push({
|
|
antiguedad: item.antiguedad,
|
|
total: item.total,
|
|
porcentaje: (
|
|
(item.total / (await totalAltoRendimiento)) *
|
|
100
|
|
).toFixed(2),
|
|
});
|
|
});
|
|
|
|
return {
|
|
escritorios: porcentajesEscritorios,
|
|
portatiles: porcentajesPortatiles,
|
|
altoRendimiento: porcentajesAltoRendimiento,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async garantia(tipo_equipo: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('e.fechaFactura >= DATE_SUB(CURDATE(), INTERVAL 3 YEAR)')
|
|
.andWhere('t.tipo_equipo IN (:...tipo_equipo)', { tipo_equipo })
|
|
.getCount();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async equipos_impesion(perifericos: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.periferico', 'p')
|
|
.where('p.periferico IN (:...perifericos)', { perifericos })
|
|
.getCount();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async equipos_impesion_group(perifericos: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.periferico', 'p')
|
|
.where('p.periferico IN (:...perifericos)', { perifericos })
|
|
.groupBy('p.periferico')
|
|
.getRawMany();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_periferico_tipoUso(perifericos: string[]): Promise<any> {
|
|
try {
|
|
const count = await this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoUso', 't')
|
|
.innerJoin('e.periferico', 'p')
|
|
.where('p.periferico IN (:...perifericos)', { perifericos })
|
|
.select(['t.tipo_uso AS uso'])
|
|
.addSelect('COUNT(*) AS total')
|
|
.groupBy('t.tipo_uso')
|
|
.getRawMany();
|
|
|
|
return count;
|
|
} catch (error) {
|
|
console.error('Error al contar equipos por tipo y uso:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async contar_perifericos_antiguedad(
|
|
impresion: string[],
|
|
digitalizacion: string[],
|
|
): Promise<{
|
|
impresion: { antiguedad: any; total: number; porcentaje: string }[];
|
|
digitalizacion: { antiguedad: any; total: number; porcentaje: string }[];
|
|
}> {
|
|
try {
|
|
// Helper para obtener total por tipos de equipo (count simple, sin group by)
|
|
const getTotalPorTipos = async (tipos: string[]): Promise<number> => {
|
|
if (!tipos || tipos.length === 0) return 0;
|
|
return this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('t.tipo_equipo IN (:...tipos)', { tipos })
|
|
.getCount();
|
|
};
|
|
|
|
// Ejecutar ambos totales en paralelo
|
|
const [totalImpresion, totalDigitalizacion] = await Promise.all([
|
|
getTotalPorTipos(impresion),
|
|
getTotalPorTipos(digitalizacion),
|
|
]);
|
|
|
|
// Obtener conteos por antiguedad para impresion
|
|
const countImpresionPromise = this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.periferico', 'p')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('p.periferico IN (:...periferico)', { periferico: impresion })
|
|
.select(['e.antiguedad AS antiguedad'])
|
|
.addSelect('COUNT(e.id_equipo) AS total')
|
|
.groupBy('e.antiguedad')
|
|
.getRawMany();
|
|
|
|
// Obtener conteos por antiguedad para digitalizacion
|
|
const countDigitalizacionPromise = this.equipoRepository
|
|
.createQueryBuilder('e')
|
|
.innerJoin('e.periferico', 'p')
|
|
.innerJoin('e.tipoEquipo', 't')
|
|
.where('p.periferico IN (:...periferico)', {
|
|
periferico: digitalizacion,
|
|
})
|
|
.select(['e.antiguedad AS antiguedad'])
|
|
.addSelect('COUNT(e.id_equipo) AS total')
|
|
.groupBy('e.antiguedad')
|
|
.getRawMany();
|
|
|
|
// Ejecutar ambas consultas en paralelo
|
|
const [countImpresion, countDigitalizacion] = await Promise.all([
|
|
countImpresionPromise,
|
|
countDigitalizacionPromise,
|
|
]);
|
|
|
|
// Tipo para salida
|
|
interface Porcentaje {
|
|
antiguedad: any;
|
|
total: number;
|
|
porcentaje: string;
|
|
}
|
|
|
|
// Mapear resultados calculando porcentajes (evitar async dentro de map/forEach)
|
|
const porcentajesImpresion: Porcentaje[] = countImpresion.map((item) => {
|
|
const total = Number(item.total) || 0;
|
|
const porcentaje =
|
|
totalImpresion > 0
|
|
? ((total / totalImpresion) * 100).toFixed(2)
|
|
: '0.00';
|
|
return {
|
|
antiguedad: item.antiguedad,
|
|
total,
|
|
porcentaje,
|
|
};
|
|
});
|
|
|
|
const porcentajesDigitalizacion: Porcentaje[] = countDigitalizacion.map(
|
|
(item) => {
|
|
const total = Number(item.total) || 0;
|
|
const porcentaje =
|
|
totalDigitalizacion > 0
|
|
? ((total / totalDigitalizacion) * 100).toFixed(2)
|
|
: '0.00';
|
|
return {
|
|
antiguedad: item.antiguedad,
|
|
total,
|
|
porcentaje,
|
|
};
|
|
},
|
|
);
|
|
|
|
return {
|
|
impresion: porcentajesImpresion,
|
|
digitalizacion: porcentajesDigitalizacion,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error en contar_perifericos_antiguedad:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async generar_reporte() {
|
|
const [
|
|
contar_equipos_de_tipo_uso,
|
|
sisitema_operativo_pc,
|
|
sisitema_operativo_mac,
|
|
sisitema_operativo_portatiles_pc,
|
|
sisitema_operativo_portatiles_mac,
|
|
sisitema_operativo_servidores,
|
|
contar_pc_procesador,
|
|
contar_mac_procesador,
|
|
contar_portatil_procesador,
|
|
contar_portatil_mac_procesador,
|
|
contar_servidor_procesador,
|
|
porcentaje_antiguedad,
|
|
garantia_escritorio,
|
|
garantia_portatiles,
|
|
garantia_servidor,
|
|
contar_impresoras,
|
|
contar_impresoras_tipo_uso,
|
|
contar_digitalizacion,
|
|
contar_contar_digitalizacion_u,
|
|
contar_perifericos_antiguedad,
|
|
] = await Promise.all([
|
|
this.contar_tipoEquipos_tipoUso(),
|
|
this.contar_tipoEquipos_sistemasOperativos(equpos_pc),
|
|
this.contar_tipoEquipos_sistemasOperativos([estritorio_mac]),
|
|
this.contar_tipoEquipos_sistemasOperativos(portatiles),
|
|
this.contar_tipoEquipos_sistemasOperativos([portatiles_mac]),
|
|
this.contar_tipoEquipos_sistemasOperativos([servidor]),
|
|
this.contar_tipoEquipos_procesador(equpos_pc),
|
|
this.contar_tipoEquipos_procesador([estritorio_mac]),
|
|
this.contar_tipoEquipos_procesador(portatiles),
|
|
this.contar_tipoEquipos_procesador([portatiles_mac]),
|
|
this.contar_tipoEquipos_procesador([servidor]),
|
|
this.contar_tipoEquipos_antiguedad(),
|
|
this.garantia(escritorio),
|
|
this.garantia(portatil),
|
|
this.garantia([servidor]),
|
|
this.equipos_impesion_group(impresoras),
|
|
this.contar_periferico_tipoUso(impresoras),
|
|
this.equipos_impesion_group(dijitales),
|
|
this.contar_periferico_tipoUso(dijitales),
|
|
this.contar_perifericos_antiguedad(impresoras, dijitales),
|
|
]);
|
|
|
|
return {
|
|
contar_equipos_de_tipo_uso,
|
|
sisitema_operativo_pc,
|
|
sisitema_operativo_mac,
|
|
sisitema_operativo_portatiles_pc,
|
|
sisitema_operativo_portatiles_mac,
|
|
sisitema_operativo_servidores,
|
|
contar_pc_procesador,
|
|
contar_mac_procesador,
|
|
contar_portatil_procesador,
|
|
contar_portatil_mac_procesador,
|
|
contar_servidor_procesador,
|
|
porcentaje_antiguedad,
|
|
garantia_escritorio,
|
|
garantia_portatiles,
|
|
garantia_servidor,
|
|
contar_impresoras,
|
|
contar_impresoras_tipo_uso,
|
|
contar_digitalizacion,
|
|
contar_contar_digitalizacion_u,
|
|
contar_perifericos_antiguedad,
|
|
};
|
|
}
|
|
|
|
async exportToClient(data: any, res: Response) {
|
|
// Aseguramos que los datos sean un arreglo de objetos planos
|
|
const rows = Array.isArray(data)
|
|
? data.map((item) => this.flattenObject(item))
|
|
: [this.flattenObject(data)];
|
|
|
|
// Crear workbook y hoja
|
|
const workbook = new ExcelJS.Workbook();
|
|
const worksheet = workbook.addWorksheet('Datos');
|
|
|
|
// Definir encabezados dinámicamente
|
|
const headers = Object.keys(rows[0] || {});
|
|
worksheet.columns = headers.map((h) => ({
|
|
header: h,
|
|
key: h,
|
|
width: 25,
|
|
}));
|
|
|
|
// Agregar filas
|
|
worksheet.addRows(rows);
|
|
|
|
// Estilizar encabezados
|
|
const headerRow = worksheet.getRow(1);
|
|
headerRow.font = { bold: true };
|
|
headerRow.alignment = { vertical: 'middle', horizontal: 'center' };
|
|
headerRow.eachCell((cell) => {
|
|
cell.border = {
|
|
top: { style: 'thin' },
|
|
left: { style: 'thin' },
|
|
bottom: { style: 'thin' },
|
|
right: { style: 'thin' },
|
|
};
|
|
});
|
|
|
|
// Configurar cabeceras HTTP
|
|
res.setHeader(
|
|
'Content-Type',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
);
|
|
res.setHeader('Content-Disposition', 'attachment; filename="reporte.xlsx"');
|
|
|
|
// Enviar directamente al cliente
|
|
await workbook.xlsx.write(res);
|
|
res.end();
|
|
}
|
|
|
|
private flattenObject(obj: any, parentKey = '', res: any = {}): any {
|
|
for (const key of Object.keys(obj || {})) {
|
|
const propName = parentKey ? `${parentKey}.${key}` : key;
|
|
const value = obj[key];
|
|
|
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
this.flattenObject(value, propName, res);
|
|
} else if (Array.isArray(value)) {
|
|
res[propName] = JSON.stringify(value);
|
|
} else {
|
|
res[propName] = value;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
|
|
let escritorio = ['ESCRITORIO PC', 'ESCRITORIO MAC OS ', 'ESCRITORIO LINUX'];
|
|
let portatil = [
|
|
'PORTÁTILES WINDOWS',
|
|
'PORTÁTILES CHROMEBOOK',
|
|
'PORTÁTILES MAC OS',
|
|
];
|
|
|
|
let equipos_mac = ['ESCRITORIO MAC OS ', 'PORTÁTILES MAC OS'];
|
|
|
|
let equpos_pc = ['ESCRITORIO PC', 'ESCRITORIO LINUX'];
|
|
let estritorio_mac = 'ESCRITORIO MAC OS ';
|
|
let portatiles_mac = 'PORTÁTILES MAC OS';
|
|
|
|
let portatiles = ['PORTÁTILES WINDOWS', 'PORTÁTILES CHROMEBOOK'];
|
|
|
|
let tabletas = ['TABLETA ANDROID', 'TABLETA iPAD OS'];
|
|
|
|
let impresoras = [
|
|
'INYECCIÓN TINTA',
|
|
'LÁSER DE ALTO VOLUMEN B/N',
|
|
'LÁSER PEQUEÑA B/N',
|
|
'LÁSER PEQUEÑA COLOR',
|
|
'MATRIZ DE PUNTOS',
|
|
'MULTIFUNCIONALES',
|
|
];
|
|
|
|
let dijitales = [
|
|
'3D',
|
|
'DIGITALIZADOR DE CAMA PLANA PARA OFICINA',
|
|
'DIGITALIZADOR CON ALIMENTADOR DE HOJAS PARA OFICINA',
|
|
];
|
|
|
|
let servidor = 'SERVIDOR';
|