2025-05-20 15:53:57 -06:00
|
|
|
import { Injectable } from '@nestjs/common';
|
2025-05-29 16:38:26 -06:00
|
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
|
|
|
import { Repository } from 'typeorm';
|
|
|
|
|
import * as csv from 'csvtojson';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
import * as path from 'path';
|
|
|
|
|
import * as moment from 'moment';
|
|
|
|
|
|
|
|
|
|
import { Programa } from './entities/programa.entity';
|
|
|
|
|
|
|
|
|
|
import { Usuario } from 'src/usuario/entities/usuario.entity';
|
|
|
|
|
import { ValidacionService } from 'src/helpers.services/validacion.service';
|
|
|
|
|
import { AuthService } from 'src/auth/auth.service';
|
|
|
|
|
import { gmail } from 'src/helpers.services/gmail.service';
|
2025-10-21 14:54:31 -06:00
|
|
|
import { SendMailDto } from 'src/helpers.services/dto/send-email.dto';
|
2025-05-20 15:53:57 -06:00
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class ProgramaService {
|
2025-05-29 16:38:26 -06:00
|
|
|
constructor(
|
|
|
|
|
@InjectRepository(Programa)
|
|
|
|
|
private programaRepo: Repository<Programa>,
|
|
|
|
|
@InjectRepository(Usuario)
|
|
|
|
|
private usuarioRepo: Repository<Usuario>,
|
2025-10-10 10:06:00 -06:00
|
|
|
private validacionService: ValidacionService,
|
|
|
|
|
private authService: AuthService,
|
|
|
|
|
private gmail: gmail,
|
2025-05-29 16:38:26 -06:00
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
async cargaMasiva(nombreArchivo: string): Promise<{ message: string }> {
|
|
|
|
|
const filePath = path.join('server/uploads', nombreArchivo);
|
|
|
|
|
const today = moment();
|
|
|
|
|
const programas = await csv().fromFile(filePath);
|
|
|
|
|
let mensaje = '';
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < programas.length; i++) {
|
|
|
|
|
const prog = programas[i];
|
|
|
|
|
mensaje += `Línea ${i + 2}\n`;
|
|
|
|
|
|
2025-10-10 10:06:00 -06:00
|
|
|
if (
|
|
|
|
|
!prog.correo ||
|
|
|
|
|
!prog.nombre ||
|
|
|
|
|
!prog.institucion ||
|
|
|
|
|
!prog.dependencia ||
|
|
|
|
|
!prog.programa ||
|
|
|
|
|
!prog.clave
|
|
|
|
|
) {
|
2025-05-29 16:38:26 -06:00
|
|
|
mensaje += 'Faltan campos requeridos. Línea omitida.\n\n';
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
this.validacionService.validarCorreo(prog.correo);
|
|
|
|
|
} catch {
|
|
|
|
|
mensaje += 'Correo inválido. Línea omitida.\n\n';
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const acatlan = prog.clave.substr(4, 7) === '-12/20-';
|
|
|
|
|
const activo = Number(prog.clave.substr(0, 4)) === today.year();
|
|
|
|
|
|
|
|
|
|
let responsable = await this.usuarioRepo.findOne({
|
2025-10-10 10:06:00 -06:00
|
|
|
where: {
|
|
|
|
|
usuario: prog.correo,
|
2025-05-29 16:38:26 -06:00
|
|
|
tipoUsuario: {
|
2025-10-10 10:06:00 -06:00
|
|
|
idTipoUsuario: 2,
|
|
|
|
|
},
|
2025-05-29 16:38:26 -06:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!responsable) {
|
2025-10-10 10:06:00 -06:00
|
|
|
const password = await this.authService.encriptar(
|
|
|
|
|
this.authService.generarPassword(),
|
|
|
|
|
);
|
2025-05-29 16:38:26 -06:00
|
|
|
const correoInfo = enviarSec(password, prog.correo, prog.nombre);
|
2025-10-10 10:06:00 -06:00
|
|
|
|
2025-05-29 16:38:26 -06:00
|
|
|
responsable = await this.usuarioRepo.create({
|
|
|
|
|
usuario: prog.correo,
|
|
|
|
|
password: password,
|
|
|
|
|
nombre: prog.nombre,
|
|
|
|
|
activo: true,
|
2025-10-10 10:06:00 -06:00
|
|
|
tipoUsuario: {
|
|
|
|
|
idTipoUsuario: 2,
|
2025-05-29 16:38:26 -06:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-21 14:54:31 -06:00
|
|
|
const sendCorreoDto: SendMailDto = {
|
2025-05-29 16:38:26 -06:00
|
|
|
to: prog.correo,
|
|
|
|
|
subject: correoInfo.subject,
|
|
|
|
|
text: correoInfo.msj,
|
2025-10-21 14:54:31 -06:00
|
|
|
fecha_recibido: new Date(),
|
2025-05-29 16:38:26 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!process.env.TOKEN_GMAIL) {
|
|
|
|
|
throw new Error('No existe el token');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
responsable = await this.usuarioRepo.save(responsable);
|
|
|
|
|
|
2025-10-21 14:54:31 -06:00
|
|
|
await this.gmail.enviarCorreo(sendCorreoDto);
|
2025-05-29 16:38:26 -06:00
|
|
|
mensaje += `Responsable creado con ID ${responsable.idUsuario} y correo ${responsable.usuario}\n`;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
mensaje += `Error creando responsable: ${err.message}\n`;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!acatlan) {
|
|
|
|
|
const existente = await this.programaRepo.findOne({
|
|
|
|
|
where: { clavePrograma: prog.clave },
|
|
|
|
|
relations: ['usuario'],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!existente) {
|
|
|
|
|
try {
|
|
|
|
|
const nuevoPrograma = this.programaRepo.create({
|
|
|
|
|
institucion: prog.institucion,
|
|
|
|
|
dependencia: prog.dependencia,
|
|
|
|
|
programa: prog.programa,
|
|
|
|
|
clavePrograma: prog.clave,
|
|
|
|
|
activo,
|
2025-10-10 10:06:00 -06:00
|
|
|
usuario: {
|
|
|
|
|
idUsuario: responsable.idUsuario,
|
|
|
|
|
},
|
2025-05-29 16:38:26 -06:00
|
|
|
});
|
|
|
|
|
const creado = await this.programaRepo.save(nuevoPrograma);
|
|
|
|
|
mensaje += `Programa ${creado.clavePrograma} asignado al usuario ${responsable.usuario}\n`;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
mensaje += `Error creando programa: ${err.message}\n`;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
mensaje += `Programa ya existe con clave ${existente.clavePrograma}. `;
|
|
|
|
|
if (existente.usuario?.usuario === prog.correo) {
|
|
|
|
|
mensaje += 'Ya pertenece a este responsable.\n';
|
|
|
|
|
} else {
|
|
|
|
|
mensaje += `Asignado a otro responsable: ${existente.usuario.usuario}\n`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const existente = await this.programaRepo.findOne({
|
|
|
|
|
where: {
|
|
|
|
|
clavePrograma: prog.clave,
|
2025-10-10 10:06:00 -06:00
|
|
|
usuario: {
|
|
|
|
|
idUsuario: responsable.idUsuario,
|
2025-05-29 16:38:26 -06:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!existente) {
|
|
|
|
|
try {
|
|
|
|
|
const nuevoPrograma = this.programaRepo.create({
|
|
|
|
|
institucion: 'UNAM',
|
|
|
|
|
dependencia: 'FES ACATLAN',
|
|
|
|
|
programa: prog.programa,
|
|
|
|
|
clavePrograma: prog.clave,
|
|
|
|
|
activo,
|
|
|
|
|
acatlan,
|
2025-10-10 10:06:00 -06:00
|
|
|
usuario: {
|
|
|
|
|
idUsuario: responsable.idUsuario,
|
2025-05-29 16:38:26 -06:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
const creado = await this.programaRepo.save(nuevoPrograma);
|
|
|
|
|
mensaje += `Programa ACATLÁN ${creado.clavePrograma} asignado a ${responsable.usuario}\n`;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
mensaje += `Error creando programa: ${err.message}\n`;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
mensaje += `Programa ACATLÁN ya pertenece a ${responsable.usuario}\n`;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-20 15:53:57 -06:00
|
|
|
|
2025-05-29 16:38:26 -06:00
|
|
|
mensaje += '\n';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs.unlinkSync(filePath);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
message: 'Se subió correctamente el archivo CSV para la carga masiva.',
|
|
|
|
|
};
|
2025-05-20 15:53:57 -06:00
|
|
|
}
|
|
|
|
|
|
2025-10-16 14:04:30 -06:00
|
|
|
async programasAdmin(idUser: number) {
|
2025-10-10 10:06:00 -06:00
|
|
|
const idUsuario = this.validacionService.validarNumeroEntero(
|
2025-10-16 14:04:30 -06:00
|
|
|
idUser,
|
2025-10-10 10:06:00 -06:00
|
|
|
'id usuario',
|
|
|
|
|
);
|
2025-05-29 16:38:26 -06:00
|
|
|
|
|
|
|
|
const usuario = await this.usuarioRepo.findOne({
|
|
|
|
|
where: { idUsuario },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!usuario) {
|
|
|
|
|
throw new Error('No existe este usuario.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (usuario.tipoUsuario.idTipoUsuario !== 2) {
|
|
|
|
|
throw new Error('No es un usuario de tipo responsable');
|
|
|
|
|
}
|
|
|
|
|
return this.programaRepo.find({
|
2025-10-10 10:06:00 -06:00
|
|
|
where: { usuario: { idUsuario } },
|
2025-05-29 16:38:26 -06:00
|
|
|
});
|
2025-05-20 15:53:57 -06:00
|
|
|
}
|
|
|
|
|
|
2025-10-16 14:04:30 -06:00
|
|
|
async programasResponsable(idUser: number) {
|
2025-10-10 10:06:00 -06:00
|
|
|
const idUsuario = this.validacionService.validarNumeroEntero(
|
2025-10-16 14:04:30 -06:00
|
|
|
idUser,
|
2025-10-10 10:06:00 -06:00
|
|
|
'id usuario',
|
|
|
|
|
);
|
2025-05-29 16:38:26 -06:00
|
|
|
|
|
|
|
|
const usuario = await this.usuarioRepo.findOne({
|
|
|
|
|
where: { idUsuario },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!usuario) {
|
|
|
|
|
throw new Error('No existe este usuario.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (usuario.tipoUsuario.idTipoUsuario !== 2) {
|
|
|
|
|
throw new Error('No es un usuario de tipo responsable');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.programaRepo.find({
|
|
|
|
|
where: {
|
2025-10-10 10:06:00 -06:00
|
|
|
usuario: { idUsuario },
|
2025-05-29 16:38:26 -06:00
|
|
|
activo: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-05-20 15:53:57 -06:00
|
|
|
}
|
|
|
|
|
|
2025-10-10 10:06:00 -06:00
|
|
|
async reasignarProgramas(idUsuario: number, correoOtroResponsable: string) {
|
|
|
|
|
const idusuario = this.validacionService.validarNumeroEntero(
|
|
|
|
|
idUsuario,
|
|
|
|
|
'id usuario',
|
|
|
|
|
);
|
2025-05-29 16:38:26 -06:00
|
|
|
const otroResponsable = this.validacionService.validarCorreo(
|
2025-10-10 10:06:00 -06:00
|
|
|
correoOtroResponsable,
|
2025-05-29 16:38:26 -06:00
|
|
|
);
|
|
|
|
|
|
2025-10-10 10:06:00 -06:00
|
|
|
let usuarioNuevo = await this.usuarioRepo.findOne({
|
|
|
|
|
where: { idUsuario: idusuario },
|
|
|
|
|
});
|
2025-05-29 16:38:26 -06:00
|
|
|
|
2025-05-30 14:37:44 -06:00
|
|
|
if (!usuarioNuevo) throw new Error('No existe este usuario.');
|
2025-10-10 10:06:00 -06:00
|
|
|
if (usuarioNuevo.tipoUsuario.idTipoUsuario != 2)
|
|
|
|
|
throw new Error('No es un usuario de tipo responsable');
|
|
|
|
|
if (usuarioNuevo.usuario === correoOtroResponsable)
|
|
|
|
|
throw new Error('Son el mismo usuario.');
|
|
|
|
|
|
|
|
|
|
let viejoResponsable = await this.usuarioRepo.findOne({
|
|
|
|
|
where: { usuario: otroResponsable },
|
|
|
|
|
});
|
2025-05-29 16:38:26 -06:00
|
|
|
|
2025-05-30 14:37:44 -06:00
|
|
|
if (!viejoResponsable) throw new Error('No existe este usuario.');
|
2025-05-29 16:38:26 -06:00
|
|
|
|
2025-05-30 14:37:44 -06:00
|
|
|
await this.programaRepo.update(
|
2025-10-10 10:06:00 -06:00
|
|
|
{ usuario: viejoResponsable },
|
|
|
|
|
{ usuario: usuarioNuevo },
|
2025-05-29 16:38:26 -06:00
|
|
|
);
|
|
|
|
|
|
2025-05-30 14:37:44 -06:00
|
|
|
// Eliminar usuario antiguo
|
2025-10-10 10:06:00 -06:00
|
|
|
await this.usuarioRepo.delete({ idUsuario: viejoResponsable.idUsuario });
|
2025-05-29 16:38:26 -06:00
|
|
|
|
2025-05-30 14:37:44 -06:00
|
|
|
return {
|
|
|
|
|
message: `Se eliminó correctamente al usuario ${correoOtroResponsable} y se reasignaron sus programas.`,
|
2025-10-10 10:06:00 -06:00
|
|
|
};
|
2025-05-30 14:37:44 -06:00
|
|
|
}
|
2025-05-20 15:53:57 -06:00
|
|
|
}
|