6 Commits

Author SHA1 Message Date
evenegas 47b3933079 se actualizaron dependencia 2026-07-29 11:22:48 -06:00
evenegas 1c6f92658d se actualizaron dependencias y corriguio movimientos 2026-07-28 23:21:30 -06:00
evenegas 08ed18ff4b agregación de distinct 2026-06-23 14:10:56 -06:00
IO 655e45a876 modified graficaPolar to search tecnico and profesor 2026-04-07 12:24:52 -05:00
IO 3c9a28a960 fixed tablaExcel 2026-04-07 12:06:50 -05:00
IO 29ffb0e327 added new ep graficaPolar 2026-03-26 09:52:09 -05:00
5 changed files with 1623 additions and 1578 deletions
+1498 -1517
View File
File diff suppressed because it is too large Load Diff
+19 -20
View File
@@ -20,14 +20,14 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^11.1.6",
"@nestjs/common": "^11.1.28",
"@nestjs/core": "^11.0.1",
"@nestjs/jwt": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/jwt": "^11.0.2",
"@nestjs/mapped-types": "^2.1.1",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/schedule": "^6.0.1",
"@nestjs/typeorm": "^11.0.0",
"@nestjs/schedule": "^6.1.3",
"@nestjs/typeorm": "^11.0.3",
"axios": "^1.13.1",
"bcryptjs": "^3.0.2",
"class-transformer": "0.5.1",
@@ -39,36 +39,35 @@
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"typeor": "^1.2.0",
"typeorm": "^0.3.27",
"xlsx": "^0.18.5"
"typeorm": "^0.3.27"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/eslintrc": "^3.3.6",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/config": "^4.0.2",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@nestjs/testing": "^11.1.28",
"@types/bcrypt": "^6.0.0",
"@types/express": "^5.0.0",
"@types/express": "^5.0.6",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/node": "^22.20.1",
"@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint": "^10.8.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"eslint-plugin-prettier": "^5.5.6",
"globals": "^16.5.0",
"jest": "^30.4.2",
"prettier": "^3.9.6",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"supertest": "^7.2.2",
"ts-jest": "^29.4.12",
"ts-loader": "^9.6.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"typescript-eslint": "^8.65.0"
},
"jest": {
"moduleFileExtensions": [
+8
View File
@@ -56,3 +56,11 @@ export class FiltrosTablaDto {
antiguedad?: string[]
}
export class FiltrosPolarDto {
@IsOptional()
@IsArray()
@IsString({ each: true })
adscripciones?: string[]
}
+17 -2
View File
@@ -19,11 +19,12 @@ import { UpdateEquipoDto } from './dto/update-equipo.dto';
import { AuthGuard } from '@nestjs/passport';
import { CreateEquipoDto } from './dto/create-equipo.dto';
import type { Response } from 'express';
import { FiltrosGraficaDto, FiltrosTablaDto } from './dto/grafica.dto';
import { FiltrosGraficaDto, FiltrosPolarDto, FiltrosTablaDto } from './dto/grafica.dto';
@Controller('equipos')
export class EquipoController {
constructor(private readonly equipoService: EquipoService) { }
@UseGuards(AuthGuard('jwt'))
@Get('buscar')
async buscarEquipos(
@@ -34,6 +35,7 @@ export class EquipoController {
return this.equipoService.buscarEquipos(filtros, +page, +limit);
}
@UseGuards(AuthGuard('jwt'))
@Post('grafica/:tipo')
async grafica(
@Param("tipo") tipo: 'antiguedad' | 'uso' | 'so' | 'procesador',
@@ -42,7 +44,16 @@ export class EquipoController {
return this.equipoService.grafica(tipo, filtros);
}
@Post('graficaPerifericos/:tipo')
@Post('graficaPolar/:tipo')
async graficaPolar(
@Param("tipo") tipo: 'ALUMNO' | 'PROFESOR' | 'ADMINISTRATIVO',
@Body() filtros: FiltrosPolarDto
) {
return this.equipoService.graficaPolar(tipo, filtros);
}
@UseGuards(AuthGuard('jwt'))
@Post('graficaPerifericos/:tipo')
async graficaPerifericos(
@Param("tipo") tipo: 'antiguedad' | 'uso' | 'so' | 'procesador',
@Body() filtros: FiltrosGraficaDto
@@ -50,6 +61,7 @@ export class EquipoController {
return this.equipoService.graficaPerifericos(tipo, filtros);
}
@UseGuards(AuthGuard('jwt'))
@Post('tabla')
async tabla(
@Body() filtros: FiltrosTablaDto
@@ -57,6 +69,7 @@ export class EquipoController {
return this.equipoService.tabla(filtros);
}
@UseGuards(AuthGuard('jwt'))
@Post('tabla/count')
async tablacount(
@Body() filtros: FiltrosTablaDto
@@ -64,6 +77,7 @@ export class EquipoController {
return this.equipoService.tablaCount(filtros);
}
@UseGuards(AuthGuard('jwt'))
@Post('excel/tabla')
async exceltabla(
@Res() res: Response,
@@ -80,6 +94,7 @@ export class EquipoController {
res.send(buffer);
}
@UseGuards(AuthGuard('jwt'))
@Post('excel/tabla/count')
async exceltablacount(
@Res() res: Response,
+80 -38
View File
@@ -28,7 +28,7 @@ import { CreateEquipoDto } from './dto/create-equipo.dto';
import { MovimientoService } from 'src/movimiento/movimiento.service';
import { Cron } from '@nestjs/schedule';
import { FiltrosGraficaDto, FiltrosTablaDto } from './dto/grafica.dto';
import { FiltrosGraficaDto, FiltrosPolarDto, FiltrosTablaDto } from './dto/grafica.dto';
@Injectable()
export class EquipoService {
@@ -1510,7 +1510,7 @@ export class EquipoService {
}
return qb
.orderBy(`equipo.adscripcion`, "DESC")
.orderBy(`equipo.inventario`, 'ASC')
.getRawMany()
}
@@ -1566,16 +1566,21 @@ export class EquipoService {
async tablaExcel(filtros?: FiltrosTablaDto) {
const qb = this.equipoRepository
.createQueryBuilder('equipo')
.select([]);
.select('equipo')
.distinct(true);
qb.leftJoin('equipo.adscripcion', 'adscripcion');
qb.leftJoin('equipo.procesador', 'procesador');
qb.leftJoin('equipo.sistemaOperativo', 'sistemaOperativo');
qb.leftJoin('equipo.sistemaOperativo', 'so');
qb.leftJoin('equipo.tipoUso', 'tipoUso');
qb.leftJoin('equipo.estado', 'estado');
qb.leftJoin('equipo.tipoEquipo', 'tipoEquipo');
qb.leftJoin('equipo.marca', 'marca');
qb.leftJoin('equipo.laboratorio', 'laboratorio');
qb.leftJoin('equipo.proyecto', 'proyecto');
qb.leftJoin('equipo.mov', 'mov');
qb.leftJoin('mov.user', 'user');
qb.addSelect('equipo.inventario', 'inventario');
qb.addSelect('adscripcion.adscripcion', 'adscripcion');
qb.addSelect('equipo.lugar', 'ubicacion');
const tieneFiltroReal = (arr?: string[]) => arr?.length && !arr.includes("0") && !arr.includes("Todos");
@@ -1583,8 +1588,6 @@ export class EquipoService {
// ADSCRIPCIONES
if (filtros?.adscripciones?.length) {
qb.addSelect('adscripcion.adscripcion', 'adscripcion');
if (tieneFiltroReal(filtros.adscripciones)) {
qb.andWhere('adscripcion.id_adscripcion IN (:...adscripciones)', {
adscripciones: filtros.adscripciones
@@ -1595,8 +1598,6 @@ export class EquipoService {
// PROCESADOR
if (filtros?.procesadores?.length) {
qb.addSelect('procesador.procesador', 'procesador');
if (tieneFiltroReal(filtros.procesadores)) {
qb.andWhere('procesador.id_procesador IN (:...procesadores)', {
procesadores: filtros.procesadores
@@ -1607,10 +1608,8 @@ export class EquipoService {
// SISTEMA OPERATIVO
if (filtros?.sistemas?.length) {
qb.addSelect('sistemaOperativo.sistema_operativo', 'so');
if (tieneFiltroReal(filtros.sistemas)) {
qb.andWhere('sistemaOperativo.id_sistema_operativo IN (:...sistemas)', {
qb.andWhere('so.id_sistema_operativo IN (:...sistemas)', {
sistemas: filtros.sistemas
});
}
@@ -1619,8 +1618,6 @@ export class EquipoService {
// USO
if (filtros?.usos?.length) {
qb.addSelect('tipoUso.tipo_uso', 'uso');
if (tieneFiltroReal(filtros.usos)) {
qb.andWhere('tipoUso.id_uso IN (:...usos)', {
usos: filtros.usos
@@ -1631,8 +1628,6 @@ export class EquipoService {
// ANTIGÜEDAD
if (filtros?.antiguedad?.length) {
qb.addSelect('equipo.antiguedad', 'antiguedad');
if (tieneFiltroReal(filtros.antiguedad)) {
qb.andWhere('equipo.antiguedad IN (:...antiguedad)', {
antiguedad: filtros.antiguedad
@@ -1641,37 +1636,41 @@ export class EquipoService {
}
const data = await qb
.orderBy(`equipo.adscripcion`, "DESC")
.orderBy(`equipo.inventario`, 'ASC')
.addOrderBy('mov.fechaMovimiento', 'ASC')
.getRawMany();
const map = new Map(data.map(item => [item.inventario, item]));
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet('Equipos');
const columns = [
{ header: 'Inventario', key: 'inventario', width: 20 },
{ header: 'Ubicación', key: 'ubicacion', width: 40 },
{ header: 'Adscripción', key: 'adscripcion', width: 40 },
{ header: 'serie', key: 'serie', width: 20 },
{ header: 'Ubicación', key: 'lugar', width: 40 },
{ header: 'Fecha factura', key: 'fecha_factura', width: 10 },
{ header: 'Antigüedad', key: 'antiguedad', width: 15 },
{ header: 'Modelo', key: 'modelo', width: 30 },
{ header: 'Marca', key: 'marca', width: 15 },
{ header: 'Estado', key: 'estado', width: 15 },
{ header: 'Adscripción', key: 'adscripcion', width: 50 },
{ header: 'Tipo de Equipo', key: 'tipo_equipo', width: 20 },
{ header: 'Sistema Operativo', key: 'sistema_operativo', width: 30 },
{ header: 'Procesador', key: 'procesador', width: 45 },
{ header: 'Tipo de Uso', key: 'tipo_uso', width: 20 },
{ header: 'Proyecto', key: 'proyecto', width: 15 },
{ header: 'Laboratorio', key: 'laboratorio', width: 15 },
{ header: 'Observaciones', key: 'observaciones', width: 20 },
{ header: 'Fecha Movimiento', key: 'fecha_movimiento', width: 10 },
{ header: 'Usuario', key: 'nombre', width: 15 },
];
if (data[0]?.procesador !== undefined) {
columns.push({ header: 'Procesador', key: 'procesador', width: 25 });
}
if (data[0]?.so !== undefined) {
columns.push({ header: 'Sistema Operativo', key: 'so', width: 25 });
}
if (data[0]?.uso !== undefined) {
columns.push({ header: 'Uso', key: 'uso', width: 20 });
}
if (data[0]?.antiguedad !== undefined) {
columns.push({ header: 'Antigüedad', key: 'antiguedad', width: 15 });
}
sheet.columns = columns;
data.forEach(row => {
map.forEach(row => {
sheet.addRow(row);
});
@@ -1744,6 +1743,49 @@ export class EquipoService {
return await workbook.xlsx.writeBuffer();
}
async graficaPolar(tipo: 'ALUMNO' | 'PROFESOR' | 'ADMINISTRATIVO', filtros?: FiltrosPolarDto) {
const usos =
tipo === 'PROFESOR'
? ['PROFESOR', 'TÉCNICO ACADEMICO']
: [tipo];
const qb = this.equipoRepository
.createQueryBuilder('equipo')
.leftJoin('equipo.tipoUso', 'tipoUso')
.leftJoin('equipo.adscripcion', 'adscripcion')
.andWhere('tipoUso.tipo_uso IN (:...usos)', { usos });
const tieneFiltroReal = (arr?: string[]) => arr?.length && !arr.includes("0") && !arr.includes("Todos");
qb.andWhere('equipo.id_periferico IS NULL')
// ADSCRIPCIONES
if (filtros?.adscripciones?.length) {
qb.addSelect('adscripcion.adscripcion', 'adscripcion');
if (tieneFiltroReal(filtros.adscripciones)) {
qb.andWhere('adscripcion.id_adscripcion IN (:...adscripciones)', {
adscripciones: filtros.adscripciones
});
}
}
return qb
.select('equipo.antiguedad', 'antiguedad')
.addSelect('COUNT(*)', 'total')
.groupBy('equipo.antiguedad')
.orderBy(`
CASE
WHEN equipo.antiguedad = 'Menor a 2 años' THEN 1
WHEN equipo.antiguedad = 'Entre 2 y 3 años' THEN 2
WHEN equipo.antiguedad = 'Entre 4 y 5 años' THEN 3
WHEN equipo.antiguedad = 'Mayor a 6 años' THEN 4
END
`)
.getRawMany();
}
}
let estado_excluidos = ['DE BAJA'];