Se agredó la entidad servActivos, se agregaron funciones para activacion de dervicio

This commit is contained in:
evenegas
2025-06-20 11:59:13 -06:00
parent bf83f9d788
commit 3eafb38f1f
11 changed files with 388 additions and 85 deletions
+35 -7
View File
@@ -1,5 +1,5 @@
// src/excel/excel.controller.ts
import { Controller, Post, Get, UseGuards, Request, Res, UploadedFile, UseInterceptors, HttpStatus } from '@nestjs/common';
import { Controller, Post, Get, UseGuards, Request, Res, UploadedFile, UseInterceptors, HttpStatus, Param, ParseIntPipe } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth } from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';
@@ -22,7 +22,8 @@ export class ExcelController {
@ExcelDocumentation.verifyExcel()
async verifyExcel(@UploadedFile() file: Express.Multer.File, @Request() req) {
const userId: number = req.user.userId; // ahora sí existe
const errors = await this.excelService.validateFile(file.buffer);
const status = await this.excelService.validateFile(file.buffer);
const errors = status.errors;
await this.movimientoService.log(
'VERIFY',
@@ -47,14 +48,17 @@ export class ExcelController {
}
try {
const result = await this.excelService.loadFile(file.buffer);
await this.movimientoService.log(
'LOAD',
//Actualizar el estado de los movimientos
if (!result) {
throw new Error('No se pudo procesar el archivo.');
}
await this.movimientoService.updateStatus(
result.id_movimiento,
'SUCCESS',
undefined,
`inserted=${result.inserted}`
);
return result;
return result
} catch (err) {
await this.movimientoService.log(
@@ -189,4 +193,28 @@ export class ExcelController {
}
}
//Agregarlo en su propio controller
@Get('movimientos')
async getMovimientos() {
const movimientos = await this.movimientoService.findAll();
return movimientos;
}
@Post('activar-servicios/:id_movimiento')
async activarServicios(
@Param('id_movimiento', ParseIntPipe) id_movimiento: number,
@Request() req,
): Promise<{ message: string }> {
const origen = req.user.origen;
if (!origen) {
throw new Error('No se encontró origen en el JWT');
}
await this.excelService.activarServicios(id_movimiento, origen);
return { message: 'Servicios activados correctamente' };
}
}
+3 -1
View File
@@ -4,10 +4,12 @@ import { ExcelController } from './excel.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario } from '../entities/entities';
import { MovimientoModule } from 'src/movimiento/movimiento.module';
import { ServActivos } from 'src/usuarios/entities/servActivos.entitie';
@Module({
imports: [
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario]),
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario, ServActivos]),
MovimientoModule
],
providers: [ExcelService],
+154 -15
View File
@@ -6,6 +6,8 @@ import { InjectRepository } from '@nestjs/typeorm';
import { CarreraUsuario, TipoUsuario, Usuario, UsuarioTipoUsuario } from '../entities/entities';
import { Genero } from '../entities/entities';
import { Carrera } from '../entities/entities';
import { MovimientoService } from 'src/movimiento/movimiento.service';
import { ServActivos } from 'src/usuarios/entities/servActivos.entitie';
export interface UsuarioRow {
cuenta: string;
@@ -40,6 +42,10 @@ export class ExcelService {
private readonly usuarioTipoUsuarioRepo: Repository<UsuarioTipoUsuario>,
@InjectRepository(TipoUsuario)
private readonly tipoUsuarioRepo: Repository<TipoUsuario>,
@InjectRepository(ServActivos)
private readonly servActivosRepo: Repository<ServActivos>,
private readonly movimientoService: MovimientoService,
// … inyecta otros repositorios si los usarás
) { }
@@ -101,23 +107,35 @@ export class ExcelService {
validateRows(rows: UsuarioRow[]) {
const errors: string[] = [];
const seen = new Set<string>();
const rowsGood: UsuarioRow[] = [];
let flagError: boolean = false;
rows.forEach((r, i) => {
const rowNum = i + 2; // por el encabezado
// Campos que no pueden quedar vacíos
['cuenta', 'nombreCompleto'].forEach(field => {
['cuenta', 'nombreCompleto', 'tipo'].forEach(field => {
const raw = (r as any)[field];
const str = raw != null ? raw.toString().trim() : '';
if (!str) {
errors.push(`Fila ${rowNum}: campo "${field}" está vacío.`);
flagError = true;
}
});
// El número de cuenta debe ser de nueve dígitos para los alumnos
if (r.cuenta && !/^\d{9}$/.test(r.cuenta.toString().trim()) && r.tipo.trim() === 'Licenciatura') {
errors.push(`Fila ${rowNum}: cuenta "${r.cuenta}" debe tener 9 dígitos.`);
flagError = true;
}
// Duplicados de "cuenta"
const cuentaStr = r.cuenta != null ? r.cuenta.toString().trim() : '';
if (seen.has(cuentaStr)) {
errors.push(`Fila ${rowNum}: cuenta duplicada "${cuentaStr}".`);
flagError = true;
} else {
seen.add(cuentaStr);
}
@@ -128,6 +146,7 @@ export class ExcelService {
const genStr = r.gen != null ? r.gen.toString().trim() : '';
if (genStr && !/^[0-9]{4}$/.test(genStr)) {
errors.push(`Fila ${rowNum}: generación inválida "${genStr}".`);
flagError = true;
}
@@ -135,16 +154,29 @@ export class ExcelService {
const fechaStr = r.fechnac != null ? r.fechnac.toString().trim() : '';
if (!/^[0-9]{8}$/.test(fechaStr)) {
errors.push(`Fila ${rowNum}: fecha de nacimiento inválida "${fechaStr}".`);
flagError = true;
}
// RFC alfanumérico
const rfcStr = r.rfc != null ? r.rfc.toString().trim() : '';
if (rfcStr && !/^[A-Z0-9]+$/.test(rfcStr)) {
errors.push(`Fila ${rowNum}: RFC contiene caracteres no válidos.`);
flagError = true;
}
if (!flagError) {
rowsGood.push(r)
} else {
flagError = false; // reset para la siguiente fila
}
});
return errors;
console.log(rowsGood);
return { errors, rowsGood };
}
@@ -153,21 +185,42 @@ export class ExcelService {
*/
async validateFile(buffer: Buffer) {
const rows = await this.parseFile(buffer);
const errs = this.validateRows(rows);
return errs;
const status = this.validateRows(rows);
return status;
}
/**
* Valida y luego persiste usuarios y relaciones básicas
*/
async loadFile(buffer: Buffer) {
const rows = await this.parseFile(buffer);
const errs = this.validateRows(rows);
if (errs.length) {
throw new BadRequestException({ errors: errs });
}
const file = await this.parseFile(buffer);
const status = this.validateRows(file);
const errs = status.errors;
const rows = status.rowsGood;
const movimiento = await this.movimientoService.log(
'LOAD',
'LOADING',
undefined
);
for (const r of rows) {
//0.1
const userExists = await this.usuarioRepo.findOne({
where: { num_cuenta: r.cuenta },
});
if (userExists) {
errs.push(`Cuenta ${r.cuenta} ya existe, se omite.`);
continue; // si ya existe, no lo insertamos
}
// 1) Género (crea o reutiliza)
let genero = await this.generoRepo.findOne({ where: { genero: r.sexo } });
if (!genero) {
@@ -200,6 +253,8 @@ export class ExcelService {
const generacion = /^[0-9]{4}$/.test(r.gen?.toString().trim())
? parseInt(r.gen.toString().trim(), 10)
: null;
// 3) Usuario
const usuario = this.usuarioRepo.create({
num_cuenta: r.cuenta,
@@ -210,9 +265,10 @@ export class ExcelService {
fecha_nacimiento: r.fechnac,
generacion: generacion,
genero,
movimiento: { id_mov: movimiento.id_mov }, // Relación con movimiento
});
await this.usuarioRepo.save(usuario);
const user = await this.usuarioRepo.save(usuario);
@@ -231,14 +287,50 @@ export class ExcelService {
});
await this.usuarioTipoUsuarioRepo.save(usuarioTipo);
// 6) ServActivos (si es necesario)
switch (r.tipo.trim()) {
case 'Licenciatura':
case 'Profesor':
const servActivos = this.servActivosRepo.create({
Red: true,
AT: true,
Correo: true,
Prestamos: true,
usuario: user,
RedStatus: 'Inactivo',
ATStatus: 'Inactivo',
CorreoStatus: 'Inactivo',
PrestamosStatus: 'Inactivo',
});
await this.servActivosRepo.save(servActivos);
break;
case 'Trabajadores':
const servActivosTrabajadores = this.servActivosRepo.create({
Red: true,
usuario: user,
RedStatus: 'Inactivo',
});
await this.servActivosRepo.save(servActivosTrabajadores);
break;
}
}
return { inserted: rows.length };
return { inserted: rows.length, id_movimiento: movimiento.id_mov, errors: errs };
}
// async generateCsv(): Promise<string> {
// const users = await this.usuarioRepo.find({
// relations: ['genero', 'carreraUsuarios'], // si quieres más info
@@ -293,6 +385,9 @@ export class ExcelService {
tipo_usuario: In(tipos),
},
},
servActivo: {
CorreoStatus: 'Inactivo', // solo los que no tienen servicio activo
}
},
relations: [
'genero',
@@ -355,6 +450,9 @@ export class ExcelService {
tipo_usuario: In(tipos),
},
},
servActivo: {
PrestamosStatus: 'Inactivo', // solo los que no tienen servicio activo
}
},
relations: [
'genero',
@@ -433,6 +531,9 @@ export class ExcelService {
tipo_usuario: In(tipos),
},
},
servActivo: {
RedStatus: 'Inactivo',
}
},
relations: [
'genero',
@@ -483,6 +584,9 @@ export class ExcelService {
tipo_usuario: In(tipos),
},
},
servActivo: {
ATStatus: 'Inactivo',
},
},
relations: [
'genero',
@@ -523,17 +627,52 @@ export class ExcelService {
//Funcion que se le debe hacer su propio módulo
async activarServicios(id_movimiento: number, origen: string): Promise<void> {
if (!['AT', 'SOLICITA', 'CORREO', 'RED'].includes(origen)) {
throw new BadRequestException(`Origen ${origen} no válido`);
}
const usuarios = await this.usuarioRepo.find({
where: { movimiento: { id_mov: id_movimiento } },
});
if (!usuarios || usuarios.length === 0) {
throw new BadRequestException('No se encontró el usuario asociado al movimiento');
}
for (const usuario of usuarios) {
const servActivos = await this.servActivosRepo.findOne({
where: { usuario: { id_usuario: usuario.id_usuario } },
});
if (!servActivos) {
throw new BadRequestException(
`No se encontraron servicios activos para el usuario con ID ${usuario.id_usuario}`,
);
}
const timestamp = 'Activo ' + new Date().toISOString();
if (origen === 'AT' && servActivos.AT) {
servActivos.ATStatus = timestamp;
} else if (origen === 'RED' && servActivos.Red) {
servActivos.RedStatus = timestamp;
} else if (origen === 'CORREO' && servActivos.Correo) {
servActivos.CorreoStatus = timestamp;
} else if (origen === 'SOLICITA' && servActivos.Prestamos) {
servActivos.PrestamosStatus = timestamp;
} else {
throw new BadRequestException(
`Origen ${origen} no válido o servicio no activo para el usuario con ID ${usuario.id_usuario}`,
);
}
await this.servActivosRepo.save(servActivos);
console.log(`Servicio ${servActivos}`);
}
}