1657 lines
48 KiB
TypeScript
1657 lines
48 KiB
TypeScript
import {
|
|
BadRequestException,
|
|
Injectable,
|
|
InternalServerErrorException,
|
|
NotFoundException,
|
|
} from '@nestjs/common';
|
|
import { CrearServicioDto } from './dto/create-servicio.dto';
|
|
import { UpdateServicioDto } from './dto/update-servicio.dto';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Between, In, Not, Repository } from 'typeorm';
|
|
import { Servicio } from './entities/servicio.entity';
|
|
import { Usuario } from 'src/usuario/entities/usuario.entity';
|
|
import { ValidacionService } from 'src/helpers.services/validacion.service';
|
|
import { gmail } from 'src/helpers.services/gmail.service';
|
|
import { DriveService } from 'src/drive/drive.service';
|
|
import * as moment from 'moment';
|
|
import { ArchivoService } from 'src/helpers.services/archivo.service';
|
|
import { convertArrayToCSV } from 'convert-array-to-csv';
|
|
import { Programa } from 'src/programa/entities/programa.entity';
|
|
import { Carrera } from 'src/carrera/entities/carrera.entity';
|
|
import { AuthService } from 'src/auth/auth.service';
|
|
import { RegistroValidadoDto } from './dto/registro-validado.dto';
|
|
import * as fs from 'fs';
|
|
import { ServiciosAdminDto } from './dto/servicios-admin.dto';
|
|
import { ServiciosResponsableDto } from './dto/servicios-responsable.dto';
|
|
import { SendMailDto } from 'src/helpers.services/dto/send-email.dto';
|
|
import { Status } from 'src/status/entities/status.entity';
|
|
import { Cron } from '@nestjs/schedule';
|
|
const {
|
|
canceladoAlumno,
|
|
canceladoResponsable,
|
|
terminoValidado,
|
|
preRegistro,
|
|
preRegistroRechazadoAlumno,
|
|
preRegistroRechazadoResponsable,
|
|
terminoRechazadoAlumno,
|
|
terminoRechazadoResponsable,
|
|
registroValidadoAlumno,
|
|
registroValidadoResponsable,
|
|
avisoTerminoAlumno,
|
|
avisoTerminoResponsable,
|
|
} = require('./../helpers.services/msjCorreos');
|
|
|
|
@Injectable()
|
|
export class ServicioService {
|
|
constructor(
|
|
@InjectRepository(Servicio)
|
|
private servicioRepo: Repository<Servicio>,
|
|
|
|
@InjectRepository(Usuario)
|
|
private usuarioRepo: Repository<Usuario>,
|
|
|
|
@InjectRepository(Programa)
|
|
private programaRepo: Repository<Programa>,
|
|
|
|
@InjectRepository(Carrera)
|
|
private carreraRepo: Repository<Carrera>,
|
|
|
|
@InjectRepository(Status)
|
|
private statusRepo: Repository<Status>,
|
|
|
|
private validacionService: ValidacionService,
|
|
|
|
private driveService: DriveService,
|
|
|
|
private gmailService: gmail,
|
|
|
|
private archivoService: ArchivoService,
|
|
|
|
private authService: AuthService,
|
|
) { }
|
|
|
|
async obtenerServicioAlumno(idUsuario: number) {
|
|
const usuario = await this.usuarioRepo.findOne({
|
|
where: { idUsuario },
|
|
relations: ['tipoUsuario'],
|
|
});
|
|
if (!usuario) {
|
|
throw new NotFoundException('No existe este usuario.');
|
|
}
|
|
|
|
if (usuario.tipoUsuario.idTipoUsuario !== 3) {
|
|
throw new NotFoundException('No es un usuario de tipo alumno.');
|
|
}
|
|
|
|
const servicio = await this.servicioRepo
|
|
.createQueryBuilder('servicio')
|
|
.leftJoinAndSelect('servicio.carrera', 'carrera')
|
|
.leftJoinAndSelect('servicio.status', 'status')
|
|
.leftJoinAndSelect('servicio.programa', 'programa')
|
|
.leftJoinAndSelect('servicio.cuestionarioAlumno2', 'ca2')
|
|
.leftJoinAndSelect('servicio.cuestionarioAlumno', 'ca')
|
|
.where('servicio.idUsuario = :idUsuario', { idUsuario })
|
|
.andWhere('servicio.idStatus != :status', { status: 10 })
|
|
.select([
|
|
'servicio.idServicio',
|
|
'servicio.creditos',
|
|
'servicio.correo',
|
|
'servicio.telefono',
|
|
'servicio.direccion',
|
|
'servicio.fechaInicio',
|
|
'servicio.fechaFin',
|
|
'servicio.fechaLiberacion',
|
|
'servicio.fechaNacimiento',
|
|
'servicio.informeGlobal',
|
|
'servicio.programaInterno',
|
|
'servicio.profesor',
|
|
'servicio.createdAt',
|
|
'servicio.idCuestionarioAlumno',
|
|
'servicio.idCuestionarioAlumno2',
|
|
|
|
'programa.idPrograma',
|
|
'programa.institucion',
|
|
'programa.dependencia',
|
|
'programa.programa',
|
|
'programa.clavePrograma',
|
|
|
|
'carrera.idCarrera',
|
|
'carrera.carrera',
|
|
|
|
'status.idStatus',
|
|
'status.status',
|
|
'ca2.idCuestionarioAlumno2',
|
|
'ca.idCuestionarioAlumno',
|
|
])
|
|
.getOne();
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este servicio social.');
|
|
}
|
|
|
|
return servicio;
|
|
}
|
|
|
|
async obtenerDetalleServicio(idServicio: number) {
|
|
const servicio = await this.servicioRepo
|
|
.createQueryBuilder('servicio')
|
|
.leftJoinAndSelect('servicio.usuario', 'usuario')
|
|
.leftJoinAndSelect('usuario.tipoUsuario', 'tipoUsuario')
|
|
.leftJoinAndSelect('servicio.carrera', 'carrera')
|
|
.leftJoinAndSelect('servicio.status', 'status')
|
|
.leftJoinAndSelect('servicio.programa', 'programa')
|
|
.leftJoinAndSelect('programa.usuario', 'usuarioPrograma')
|
|
.leftJoinAndSelect('servicio.cuestionarioAlumno2', 'ca2')
|
|
.leftJoinAndSelect('servicio.cuestionarioPrograma2', 'cp2')
|
|
.leftJoinAndSelect('servicio.cuestionarioPrograma', 'cp')
|
|
.leftJoinAndSelect('servicio.cuestionarioAlumno', 'ca')
|
|
.where('servicio.idServicio = :idServicio', { idServicio })
|
|
.select([
|
|
'servicio.idServicio',
|
|
'servicio.creditos',
|
|
'servicio.correo',
|
|
'servicio.telefono',
|
|
'servicio.direccion',
|
|
'servicio.fechaInicio',
|
|
'servicio.fechaFin',
|
|
'servicio.fechaLiberacion',
|
|
'servicio.fechaNacimiento',
|
|
'servicio.cartaAceptacion',
|
|
'servicio.cartaTermino',
|
|
'servicio.informeGlobal',
|
|
'servicio.programaInterno',
|
|
'servicio.profesor',
|
|
'servicio.vistoBuenoAcatlan',
|
|
'servicio.createdAt',
|
|
'servicio.idCuestionarioAlumno',
|
|
'servicio.idCuestionarioAlumno2',
|
|
'servicio.idCuestionarioPrograma',
|
|
'servicio.idCuestionarioPrograma2',
|
|
|
|
'usuario.idUsuario',
|
|
'usuario.usuario',
|
|
'usuario.nombre',
|
|
|
|
'tipoUsuario.idTipoUsuario',
|
|
'carrera.idCarrera',
|
|
'carrera.carrera',
|
|
|
|
'status.idStatus',
|
|
'status.status',
|
|
|
|
'programa.idPrograma',
|
|
'programa.institucion',
|
|
'programa.dependencia',
|
|
'programa.programa',
|
|
'programa.clavePrograma',
|
|
'programa.acatlan',
|
|
|
|
'usuarioPrograma.idUsuario',
|
|
'usuarioPrograma.usuario',
|
|
'usuarioPrograma.nombre',
|
|
|
|
'ca2.idCuestionarioAlumno2',
|
|
'ca.idCuestionarioAlumno',
|
|
'cp2.idCuestionarioPrograma2',
|
|
'cp.idCuestionarioPrograma'
|
|
])
|
|
.getOne();
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este servicio social.');
|
|
}
|
|
|
|
return servicio;
|
|
}
|
|
|
|
async cancelarServicio(body: { idServicio: number; mensaje: string }) {
|
|
const idServicio = this.validacionService.validarNumeroEntero(
|
|
body.idServicio,
|
|
'id servicio',
|
|
);
|
|
const mensaje = this.validacionService.validarAlfanumerico(
|
|
body.mensaje,
|
|
'mensaje',
|
|
true,
|
|
800,
|
|
);
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: [
|
|
'usuario', // alumno
|
|
'programa',
|
|
'programa.usuario', // responsable
|
|
'status', // Falto agregar la relacion de status
|
|
],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
}
|
|
|
|
// Agregamos una validación para el status extra
|
|
if (!servicio.status) {
|
|
throw new BadRequestException('El Servicio Social no tiene un estatus válido.');
|
|
}
|
|
|
|
if (servicio.status.idStatus === 10) {
|
|
throw new BadRequestException('Este Servicio Social ya fue cancelado.');
|
|
}
|
|
|
|
if (servicio.status.idStatus === 6) {
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya fue finalizado, no se puede cancelar.',
|
|
);
|
|
}
|
|
|
|
const alumno = servicio.usuario;
|
|
const responsable = servicio.programa.usuario;
|
|
|
|
const correoAlumno = canceladoAlumno(mensaje, alumno.nombre);
|
|
const correoResponsable = canceladoResponsable(mensaje, alumno.nombre);
|
|
|
|
const sendCorreoAlumnoDto: SendMailDto = {
|
|
to: servicio.correo,
|
|
subject: correoAlumno.subject,
|
|
fecha_recibido: new Date(),
|
|
text: correoAlumno.msj,
|
|
html: '',
|
|
adjuntos: undefined,
|
|
};
|
|
|
|
const sendCorreoResponsableDto: SendMailDto = {
|
|
to: responsable.usuario,
|
|
subject: correoResponsable.subject,
|
|
fecha_recibido: new Date(),
|
|
text: correoResponsable.msj,
|
|
html: '',
|
|
adjuntos: undefined,
|
|
};
|
|
|
|
if (servicio.correo) {
|
|
await this.gmailService.enviarCorreo(sendCorreoAlumnoDto);
|
|
}
|
|
|
|
if (responsable.usuario) {
|
|
await this.gmailService.enviarCorreo(sendCorreoResponsableDto);
|
|
}
|
|
|
|
// Desactivar al usuario (alumno)
|
|
await this.usuarioRepo.update(alumno.idUsuario, {
|
|
activo: false,
|
|
password: null,
|
|
});
|
|
|
|
// Cambiar estado del servicio
|
|
await this.servicioRepo.update(idServicio, { status: { idStatus: 10 } });
|
|
|
|
return {
|
|
message: 'Se canceló correctamente este Servicio Social.',
|
|
};
|
|
}
|
|
|
|
async cartaTermino(idServ: number, file: string) {
|
|
const idServicio = this.validacionService.validarNumeroEntero(
|
|
idServ,
|
|
'id servicio',
|
|
);
|
|
|
|
const path = `./server/uploads/${this.validacionService.validacionBasicaStr(
|
|
file,
|
|
'archivo',
|
|
true,
|
|
1000,
|
|
)}`;
|
|
|
|
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['status'],
|
|
});
|
|
console.log('Servicio encontrado:', servicio);
|
|
if (!servicio) {
|
|
throw new NotFoundException('Este servicio no existe.');
|
|
}
|
|
|
|
if (servicio.cartaAceptacion) {
|
|
throw new BadRequestException('Ya se subió la Carta de Aceptación.');
|
|
}
|
|
|
|
// Aquí validas los estados igual que antes
|
|
switch (servicio.status.idStatus) {
|
|
case 7:
|
|
break;
|
|
case 1:
|
|
throw new BadRequestException(
|
|
'Esta función solo puede usarse cuando el estatus del Servicio Social sea 7.',
|
|
);
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya pasó la fase de subir la Carta de Aceptación.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
case 8:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado. No se puede avanzar hasta que se corrija lo necesario.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social fue cancelado. Comunícate con COESI para solucionar tu problema.',
|
|
);
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
// Subir archivo al drive
|
|
const uploadPath = await this.driveService.uploadFile(
|
|
path,
|
|
'Carta_Aceptacion.pdf',
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
if (!uploadPath) {
|
|
throw new BadRequestException(
|
|
'No se pudo subir el archivo, intenta más tarde.',
|
|
);
|
|
}
|
|
// Actualizar servicio
|
|
await this.servicioRepo.update(idServicio, {
|
|
cartaAceptacion: uploadPath,
|
|
status: { idStatus: 1 },
|
|
});
|
|
|
|
return {
|
|
message: 'Se subió la Carta de Aceptación correctamente.',
|
|
};
|
|
}
|
|
|
|
async subirCartaTermino(
|
|
idServicioParam: number,
|
|
archivo: Express.Multer.File,
|
|
): Promise<{ message: string }> {
|
|
|
|
const idServicio: number =
|
|
this.validacionService.validarNumeroEntero(idServicioParam, 'id servicio');
|
|
|
|
if (!archivo) {
|
|
throw new BadRequestException('No se recibió el archivo');
|
|
}
|
|
|
|
if (archivo.mimetype !== 'application/pdf') {
|
|
throw new BadRequestException('El archivo debe ser PDF');
|
|
}
|
|
|
|
const rutaArchivo = `./server/uploads/${archivo.filename}`;
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('Este servicio no existe.');
|
|
}
|
|
|
|
if (!servicio.status?.idStatus) {
|
|
throw new BadRequestException('El servicio no tiene un status válido.');
|
|
}
|
|
|
|
if (servicio.cartaTermino) {
|
|
throw new BadRequestException('Ya se subió la Carta de Termino.');
|
|
}
|
|
|
|
let archivoSubido: string;
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 4:
|
|
case 8:
|
|
try {
|
|
archivoSubido = await this.driveService.uploadFile(
|
|
rutaArchivo,
|
|
'Carta_Termino.pdf',
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
} catch (err) {
|
|
if (fs.existsSync(rutaArchivo)) fs.unlinkSync(rutaArchivo);
|
|
throw err;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
throw new BadRequestException(
|
|
'Aún no se puede subir la Carta de Termino a este Servicio Social.',
|
|
);
|
|
case 5:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya pasó la fase de subir la Carta de Termino.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
case 7:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social está cancelado.',
|
|
);
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
if (!archivoSubido) {
|
|
throw new InternalServerErrorException('Error al subir archivo.');
|
|
}
|
|
|
|
await this.servicioRepo.update(idServicio, {
|
|
cartaTermino: archivoSubido,
|
|
});
|
|
|
|
const resultadoPreTermino =
|
|
await this.validacionService.validarPreTermino(idServicio);
|
|
|
|
return {
|
|
message: `Se subió la Carta de Termino correctamente. ${resultadoPreTermino}`,
|
|
};
|
|
}
|
|
|
|
|
|
async generarGustavoBazPrada(yearParam: number): Promise<string> {
|
|
// 🔹 Validar año
|
|
const year: number = this.validacionService.validarNumero(
|
|
String(yearParam),
|
|
'año',
|
|
true,
|
|
4,
|
|
);
|
|
|
|
// Los transformo a string para hacer la consulta
|
|
//const inicio = moment(`${year}-01-31`).toDate();
|
|
//const fin = moment(`${year + 1}-01-31`).toDate();
|
|
const inicio = moment(`${year}-01-31`).format('YYYY-MM-DD');
|
|
const fin = moment(`${year + 1}-01-31`).format('YYYY-MM-DD');
|
|
const path: string = `server/uploads/${year}_gustavo_baz_prada.csv`;
|
|
const data: any[] = [];
|
|
|
|
// 🔹 Buscar servicios liberados en el año
|
|
const servicios: Servicio[] = await this.servicioRepo.find({
|
|
where: {
|
|
fechaLiberacion: Between(inicio, fin),
|
|
},
|
|
relations: ['usuario', 'carrera'],
|
|
order: { fechaLiberacion: 'ASC' },
|
|
});
|
|
|
|
// 🔹 Formatear datos
|
|
servicios.forEach((servicio) => {
|
|
data.push({
|
|
numeroCuenta: servicio.usuario.usuario,
|
|
nombre: servicio.usuario.nombre,
|
|
licenciatura: servicio.carrera.carrera,
|
|
correo: servicio.correo,
|
|
fechaLiberacion: this.archivoService.crearDDMMAAAA(
|
|
servicio.fechaLiberacion,
|
|
),
|
|
});
|
|
});
|
|
|
|
// 🔹 Eliminar archivo existente y crear CSV
|
|
try {
|
|
await this.archivoService.eliminarArchivo(path);
|
|
} catch (err) {
|
|
console.log('Error eliminando archivo:', err);
|
|
}
|
|
|
|
await this.archivoService.crearArchivo(path, convertArrayToCSV(data));
|
|
|
|
return path;
|
|
}
|
|
|
|
async subirInformeGlobal(
|
|
idServicioParam: number,
|
|
archivo: Express.Multer.File,
|
|
): Promise<{ message: string }> {
|
|
// 🔹 Validar idServicio
|
|
const idServicio: number = this.validacionService.validarNumeroEntero(
|
|
idServicioParam,
|
|
'id servicio',
|
|
);
|
|
|
|
// 🔹 Validar archivo y generar path local
|
|
const rutaArchivo: string = `./server/uploads/${this.validacionService.validacionBasicaStr(
|
|
archivo.filename,
|
|
'archivo',
|
|
true,
|
|
1000,
|
|
)}`;
|
|
|
|
// 🔹 Buscar servicio
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('Este servicio no existe.');
|
|
}
|
|
|
|
if (servicio.informeGlobal) {
|
|
throw new BadRequestException('Ya se subió el Informe Global.');
|
|
}
|
|
|
|
// 🔹 Validar status y subir archivo si corresponde
|
|
let archivoSubido;
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 4:
|
|
case 9:
|
|
archivoSubido = await this.driveService.uploadFile(
|
|
rutaArchivo,
|
|
'Informe_Global.pdf',
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
throw new BadRequestException(
|
|
'Aún no se puede subir el Informe Global a este Servicio Social.',
|
|
);
|
|
case 5:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya pasó la fase de subir el Informe Global.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
case 7:
|
|
case 8:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado. No se puede avanzar hasta que se corrija lo necesario.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social está cancelado. Comunícate con COESI para solucionar tu problema.',
|
|
);
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
// 🔹 Actualizar el servicio con el informe global
|
|
await this.servicioRepo.update(idServicio, {
|
|
informeGlobal: archivoSubido,
|
|
});
|
|
|
|
// 🔹 Ejecutar validaciones adicionales (pre-termino)
|
|
const resultadoPreTermino =
|
|
await this.validacionService.validarPreTermino(idServicio);
|
|
|
|
// 🔹 Retornar mensaje
|
|
return {
|
|
message: `Se subió el Informe Global correctamente. ${resultadoPreTermino}`,
|
|
};
|
|
}
|
|
|
|
async liberarServicio(
|
|
idServicioParam: number,
|
|
vistoBuenoAcatlan: boolean = false,
|
|
): Promise<{ message: string }> {
|
|
// 🔹 Validar idServicio
|
|
const idServicio: number = this.validacionService.validarNumeroEntero(
|
|
idServicioParam,
|
|
'id servicio',
|
|
);
|
|
|
|
// 🔹 Buscar servicio con relaciones
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'programa', 'status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
}
|
|
|
|
// 🔹 Validación para programas Acatlán
|
|
if (servicio.programa.acatlan && !vistoBuenoAcatlan) {
|
|
throw new BadRequestException(
|
|
'El programa de este Servicio Social es Acatlán Contigo y no se envió la validación correspondiente.',
|
|
);
|
|
}
|
|
|
|
// 🔹 Enviar correo según status
|
|
switch (servicio.status.idStatus) {
|
|
case 5:
|
|
const correoAlumno = terminoValidado(servicio.usuario.nombre);
|
|
|
|
if (servicio.correo) {
|
|
await this.gmailService.enviarCorreo({
|
|
to: servicio.correo,
|
|
subject: correoAlumno.subject,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social aún no puede pasar a Liberación.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya se encuentra en Liberación.',
|
|
);
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado. No se puede aceptar hasta que se corrija lo necesario.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException('Este Servicio Social está cancelado.');
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
// 🔹 Actualizar el servicio
|
|
await this.servicioRepo.update(idServicio, {
|
|
status: { idStatus: 6 },
|
|
fechaLiberacion: moment().format('YYYY-MM-DD'), // lo mismo pasamos a string antes como toDate
|
|
vistoBuenoAcatlan: vistoBuenoAcatlan ? true : false,
|
|
});
|
|
|
|
return {
|
|
message:
|
|
'Se cambió de estatus correctamente y se envió un correo al alumno informándole de su liberación.',
|
|
};
|
|
}
|
|
|
|
async registrarNuevoServicio(
|
|
dto: CrearServicioDto,
|
|
file: Express.Multer.File,
|
|
): Promise<{ message: string }> {
|
|
// 🔹 Validaciones
|
|
|
|
// Agregue una validacion para el archivo
|
|
if (!file) {
|
|
throw new BadRequestException('No se ha proporcionado un archivo.');
|
|
}
|
|
|
|
/* Codigo anterior
|
|
const archivoPath = `./server/uploads/${this.validacionService.validacionBasicaStr(file.filename, 'archivo', true, 1000)}`;
|
|
*/
|
|
// Hacemos una validacion en el nombre
|
|
const nombreArchivo = `./server/uploads/${this.validacionService.validacionBasicaStr(file.filename, 'archivo', true, 1000)}`;
|
|
|
|
const archivoPath = nombreArchivo;
|
|
|
|
// Validacion de tipo de archivo
|
|
if (file.mimetype !== 'application/pdf') {
|
|
throw new BadRequestException('La carta debe ser un archivo PDF.');
|
|
}
|
|
|
|
// Validacion de tamanio
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
throw new BadRequestException('La carta debe ser menor a 5MB.');
|
|
}
|
|
|
|
const progInterno = dto.programaInterno
|
|
? this.validacionService.validarAlfanumerico(
|
|
dto.programaInterno,
|
|
'programa interno',
|
|
true,
|
|
250,
|
|
)
|
|
: '';
|
|
const prof = dto.profesor
|
|
? this.validacionService.validarTexto(dto.profesor, 'profesor', true, 50)
|
|
: '';
|
|
|
|
// 🔹 Validar Usuario
|
|
const usuario = await this.usuarioRepo.findOne({
|
|
where: { idUsuario: dto.idUsuario }, relations: ['tipoUsuario'],
|
|
});
|
|
if (!usuario)
|
|
throw new NotFoundException('Este alumno no existe en la db.');
|
|
if (usuario.tipoUsuario.idTipoUsuario !== 3)
|
|
throw new BadRequestException('Este usuario no es de tipo Alumno.');
|
|
|
|
// 🔹 Validar Programa
|
|
const programa = await this.programaRepo.findOne({
|
|
where: { idPrograma: dto.idPrograma },
|
|
});
|
|
if (!programa)
|
|
throw new NotFoundException('Este programa no existe en la db.');
|
|
|
|
// 🔹 Validar Carrera
|
|
const carrera = await this.carreraRepo.findOne({
|
|
where: { idCarrera: dto.idCarrera },
|
|
});
|
|
if (!carrera)
|
|
throw new NotFoundException('Esta carrera no existe en la db.');
|
|
|
|
// 🔹 Verificar Servicio activo
|
|
const servicioExistente = await this.servicioRepo.findOne({
|
|
where: {
|
|
usuario: { idUsuario: dto.idUsuario },
|
|
status: { idStatus: Not(10) },
|
|
},
|
|
});
|
|
if (servicioExistente)
|
|
throw new BadRequestException(
|
|
'Este alumno ya tiene un Servicio Social activo.',
|
|
);
|
|
|
|
// 🔹 Crear Servicio
|
|
const nuevoServicio = this.servicioRepo.create({
|
|
usuario,
|
|
programa,
|
|
carrera,
|
|
creditos: dto.creditos.toString(),
|
|
correo: dto.correo,
|
|
fechaInicio: dto.fechaInicio,
|
|
fechaFin: dto.fechaFin,
|
|
carpeta: '',
|
|
cartaAceptacion: '',
|
|
profesor: prof,
|
|
programaInterno: progInterno,
|
|
status: { idStatus: 1 },
|
|
});
|
|
|
|
await this.servicioRepo.save(nuevoServicio);
|
|
|
|
// 🔹 Crear carpeta y subir carta de aceptación
|
|
const carpeta = await this.driveService.mkDir(dto.numeroCuenta);
|
|
const cartaPath = await this.driveService.uploadFile(
|
|
archivoPath,
|
|
'Carta_Aceptacion.pdf',
|
|
'application/pdf',
|
|
carpeta,
|
|
);
|
|
if (!carpeta || !cartaPath) {
|
|
throw new BadRequestException(
|
|
'No se pudo crear la carpeta o subir la carta, intenta más tarde.',
|
|
);
|
|
}
|
|
|
|
// 🔹 Actualizar servicio con carpeta y carta
|
|
await this.servicioRepo.update(nuevoServicio.idServicio, {
|
|
carpeta,
|
|
cartaAceptacion: cartaPath,
|
|
});
|
|
|
|
return { message: 'Se pre-registró correctamente a este alumno.' };
|
|
}
|
|
|
|
async rechazar(
|
|
idServicio: number,
|
|
mensaje: string,
|
|
): Promise<{ message: string }> {
|
|
let correoResponsable: any;
|
|
let correoAlumno: any;
|
|
let emailResponsable = '';
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'programa', 'programa.usuario', 'status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
}
|
|
|
|
const statusId = servicio.status.idStatus;
|
|
|
|
switch (statusId) {
|
|
case 1:
|
|
correoAlumno = preRegistroRechazadoAlumno(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
|
|
correoResponsable = preRegistroRechazadoResponsable(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
|
|
emailResponsable = servicio.programa.usuario.usuario;
|
|
|
|
// correo alumno
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoAlumno.subject,
|
|
to: servicio.correo,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 8:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'No se puede rechazar la Carta de Aceptación en este punto del Servicio Social.',
|
|
);
|
|
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
|
|
case 7:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya tiene la Carta de Aceptación rechazada.',
|
|
);
|
|
|
|
case 10:
|
|
throw new BadRequestException('Este Servicio Social fue cancelado.');
|
|
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
// correo responsable
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoResponsable.subject,
|
|
to: emailResponsable,
|
|
text: correoResponsable.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
|
|
const statusRechazado = await this.statusRepo.findOneBy({ idStatus: 7 });
|
|
|
|
if (!statusRechazado) {
|
|
throw new NotFoundException('El estatus de rechazado no existe.');
|
|
}
|
|
|
|
await this.driveService.deleteFile(servicio.cartaAceptacion)
|
|
|
|
await this.servicioRepo.update(idServicio, {
|
|
status: statusRechazado,
|
|
cartaAceptacion: '',
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
message: 'Se rechazó correctamente la Carta de Aceptación.',
|
|
};
|
|
}
|
|
|
|
|
|
async rechazarInforme(
|
|
idServicio: number,
|
|
mensaje: string,
|
|
): Promise<{ message: string }> {
|
|
let correoResponsable: any;
|
|
let correoAlumno: any;
|
|
let emailResponsable = '';
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'programa', 'programa.usuario', 'status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
}
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 5:
|
|
correoAlumno = terminoRechazadoAlumno(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
correoResponsable = terminoRechazadoResponsable(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
emailResponsable = servicio.programa.usuario.usuario;
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoAlumno.subject,
|
|
to: servicio.correo,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
throw new BadRequestException(
|
|
'Aún no se puede rechazar el Informe Global.',
|
|
);
|
|
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
|
|
case 7:
|
|
case 8:
|
|
throw new BadRequestException(
|
|
'No se puede rechazar el Informe Global en este punto del Servicio Social.',
|
|
);
|
|
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya tiene el Informe Global rechazado.',
|
|
);
|
|
|
|
case 10:
|
|
throw new BadRequestException('Este Servicio Social fue cancelado.');
|
|
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoResponsable.subject,
|
|
to: emailResponsable,
|
|
text: correoResponsable.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
|
|
if (!servicio.informeGlobal) {
|
|
throw new Error("no hay Informe Global")
|
|
}
|
|
|
|
await this.driveService.deleteFile(servicio.informeGlobal)
|
|
|
|
await this.servicioRepo.update(idServicio, {
|
|
status: { idStatus: 9 },
|
|
informeGlobal: '',
|
|
});
|
|
|
|
return {
|
|
message: 'Se rechazó correctamente el Informe Global.',
|
|
};
|
|
}
|
|
|
|
|
|
async rechazarTermino(
|
|
idServicio: number,
|
|
mensaje: string,
|
|
): Promise<{ message: string }> {
|
|
let correoResponsable: any;
|
|
let correoAlumno: any;
|
|
let emailResponsable = '';
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'programa', 'programa.usuario', 'status'],
|
|
});
|
|
|
|
if (!servicio) {
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
}
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 5:
|
|
correoAlumno = terminoRechazadoAlumno(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
correoResponsable = terminoRechazadoResponsable(
|
|
mensaje,
|
|
servicio.usuario.nombre,
|
|
);
|
|
emailResponsable = servicio.programa.usuario.usuario;
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoAlumno.subject,
|
|
to: servicio.correo,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
throw new BadRequestException(
|
|
'Aún no se puede rechazar la Carta de Término.',
|
|
);
|
|
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
|
|
case 7:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'No se puede rechazar la Carta de Término en este punto del Servicio Social.',
|
|
);
|
|
|
|
case 8:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya tiene la Carta de Término rechazada.',
|
|
);
|
|
|
|
case 10:
|
|
throw new BadRequestException('Este Servicio Social fue cancelado.');
|
|
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoResponsable.subject,
|
|
to: emailResponsable,
|
|
text: correoResponsable.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
|
|
if (!servicio.cartaTermino) {
|
|
throw new Error("No hay Carta Termino")
|
|
}
|
|
|
|
await this.driveService.deleteFile(servicio.cartaTermino)
|
|
|
|
await this.servicioRepo.update(idServicio, {
|
|
status: { idStatus: 8 },
|
|
cartaTermino: '',
|
|
});
|
|
|
|
return {
|
|
message: 'Se rechazó correctamente la Carta de Término.',
|
|
};
|
|
}
|
|
|
|
|
|
async registro(idServicio: number): Promise<{ message: string }> {
|
|
let password = await this.authService.generarPassword();
|
|
if (process.env.MODE === 'pruebas') password = 'qwertyui';
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'status'],
|
|
});
|
|
|
|
if (!servicio)
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
|
|
let correoData: any;
|
|
let idUsuario: number;
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 1:
|
|
correoData = preRegistro(password, servicio.usuario.nombre);
|
|
idUsuario = servicio.usuario.idUsuario;
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoData.subject,
|
|
to: servicio.correo,
|
|
text: correoData.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
break;
|
|
|
|
case 2:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya se encuentra en Registro.',
|
|
);
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya paso por el Registro.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado. No se puede aceptar hasta que se corriga lo necesario.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException('Este Servicio Social fue cancelado.');
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
// Actualizar contraseña del alumno y activarlo
|
|
await this.usuarioRepo.update(idUsuario, {
|
|
password: await this.authService.encriptar(password),
|
|
activo: true,
|
|
});
|
|
|
|
// Cambiar estatus del Servicio Social
|
|
await this.servicioRepo.update(idServicio, { status: { idStatus: 2 } });
|
|
|
|
return {
|
|
message:
|
|
'Se cambió de estatus correctamente y se envió un correo al alumno con sus credenciales.',
|
|
};
|
|
}
|
|
|
|
async registroValidado(
|
|
dto: RegistroValidadoDto,
|
|
): Promise<{ message: string }> {
|
|
const idServicio = dto.idServicio;
|
|
const fechaNacimiento = dto.fechaNacimiento;
|
|
const telefono = dto.telefono;
|
|
const direccion = dto.direccion;
|
|
|
|
const servicio = await this.servicioRepo.findOne({
|
|
where: { idServicio },
|
|
relations: ['usuario', 'programa', 'programa.usuario', 'status'],
|
|
});
|
|
|
|
if (!servicio)
|
|
throw new NotFoundException('No existe este Servicio Social.');
|
|
|
|
let correoAlumno: any;
|
|
let correoResponsable: any;
|
|
let emailResponsable: string;
|
|
|
|
// const sendCorreoResponsableDto: SendMailDto = {
|
|
// to: correoResponsable,
|
|
// subject: correoResponsable.subject,
|
|
// fecha_recibido: new Date(),
|
|
// text: correoResponsable.msj,
|
|
// html: '',
|
|
// adjuntos: undefined,
|
|
// };
|
|
|
|
// const sendCorreoAlumnoDto: SendMailDto = {
|
|
// to: servicio.correo,
|
|
// subject: correoAlumno.subject,
|
|
// fecha_recibido: new Date(),
|
|
// text: correoAlumno.msj,
|
|
// html: '',
|
|
// adjuntos: undefined,
|
|
// };
|
|
|
|
switch (servicio.status.idStatus) {
|
|
case 2:
|
|
// correoAlumno = registroValidadoAlumno(servicio.usuario.nombre);
|
|
// correoResponsable = registroValidadoResponsable(
|
|
// servicio.usuario.nombre,
|
|
// );
|
|
// emailResponsable = servicio.programa.usuario.usuario;
|
|
// await this.gmailService.enviarCorreo({
|
|
// subject: correoAlumno.subject,
|
|
// to: servicio.correo,
|
|
// text: correoAlumno.msj,
|
|
// fecha_recibido: new Date(),
|
|
// });
|
|
// break;
|
|
correoAlumno = registroValidadoAlumno(servicio.usuario.nombre);
|
|
correoResponsable = registroValidadoResponsable(
|
|
servicio.usuario.nombre,
|
|
);
|
|
emailResponsable = servicio.programa.usuario.usuario;
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoAlumno.subject,
|
|
to: servicio.correo,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
break;
|
|
|
|
case 1:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social aún no puede pasar a Registro Validado.',
|
|
);
|
|
case 3:
|
|
throw new BadRequestException(
|
|
'Este servicio ya se encuentra en Registro Validado.',
|
|
);
|
|
case 4:
|
|
case 5:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social ya pasó por el Registro Validado.',
|
|
);
|
|
case 6:
|
|
throw new BadRequestException('Este Servicio Social ya finalizó.');
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social se encuentra rechazado. Comunícate con COESI.',
|
|
);
|
|
case 10:
|
|
throw new BadRequestException(
|
|
'Este Servicio Social fue cancelado. Comunícate con COESI.',
|
|
);
|
|
default:
|
|
throw new BadRequestException('Id status no válido.');
|
|
}
|
|
|
|
if (!correoResponsable || !emailResponsable) {
|
|
throw new InternalServerErrorException(
|
|
'Error al generar correo para el responsable',
|
|
);
|
|
}
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoResponsable.subject,
|
|
to: emailResponsable,
|
|
text: correoResponsable.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
|
|
// await this.gmailService.enviarCorreo({
|
|
// subject: correoResponsable.subject,
|
|
// to: emailResponsable,
|
|
// text: correoResponsable.msj,
|
|
// fecha_recibido: new Date(),
|
|
// });
|
|
|
|
// Determinar estatus según modo
|
|
const tempStatus = process.env.MODE === 'pruebas' ? 4 : 3;
|
|
|
|
await this.servicioRepo.update(idServicio, {
|
|
status: { idStatus: tempStatus },
|
|
direccion,
|
|
telefono,
|
|
fechaNacimiento,
|
|
});
|
|
|
|
return {
|
|
message: 'Haz terminado el registro de tu Servicio Social correctamente.',
|
|
};
|
|
}
|
|
|
|
// Pasamos el string antes tenia Date
|
|
async generarReporte(inicio: string, fin: string): Promise<string> {
|
|
const path = `server/uploads/reporte.csv`;
|
|
const data: any[] = [];
|
|
|
|
const servicios = await this.servicioRepo.find({
|
|
where: {
|
|
fechaInicio: Between(inicio, fin),
|
|
},
|
|
relations: ['usuario', 'programa', 'carrera', 'status'],
|
|
order: { fechaInicio: 'ASC' },
|
|
});
|
|
|
|
servicios.forEach((s) => {
|
|
data.push({
|
|
numeroCuenta: s.usuario.usuario,
|
|
nombre: s.usuario.nombre,
|
|
licenciatura: s.carrera.carrera,
|
|
correo: s.correo,
|
|
fechaInicio: this.archivoService.crearDDMMAAAA(s.fechaInicio),
|
|
fechaFin: this.archivoService.crearDDMMAAAA(s.fechaFin),
|
|
fechaLiberacion: s.fechaLiberacion
|
|
? this.archivoService.crearDDMMAAAA(s.fechaLiberacion)
|
|
: '',
|
|
institucion: s.programa.institucion,
|
|
dependencia: s.programa.dependencia,
|
|
programa: s.programa.programa,
|
|
profesor: s.profesor,
|
|
clave: s.programa.clavePrograma,
|
|
status: s.status.status,
|
|
});
|
|
});
|
|
|
|
// Eliminar archivo existente si existe
|
|
if (fs.existsSync(path)) {
|
|
fs.unlinkSync(path);
|
|
}
|
|
|
|
// Crear CSV
|
|
fs.writeFileSync(path, convertArrayToCSV(data));
|
|
|
|
return path;
|
|
}
|
|
|
|
async obtenerServiciosAdmin(dto: ServiciosAdminDto) {
|
|
const pagina = dto.pagina ? dto.pagina : 1;
|
|
const limite = 25; // limite de paginacion
|
|
const whereStatus = dto.idStatus ? { idStatus: dto.idStatus } : {};
|
|
const nombre = dto.nombre ? dto.nombre : '';
|
|
const numeroCuenta = dto.numeroCuenta ? dto.numeroCuenta : '';
|
|
|
|
const query = this.servicioRepo
|
|
.createQueryBuilder('servicio')
|
|
.leftJoinAndSelect('servicio.usuario', 'usuario')
|
|
.leftJoinAndSelect('servicio.carrera', 'carrera')
|
|
.leftJoinAndSelect('servicio.status', 'status')
|
|
//.leftJoinAndSelect('servicio.cuestionarioAlumno2', 'ca2')
|
|
//.leftJoinAndSelect('servicio.cuestionarioPrograma2', 'cp2')
|
|
//.leftJoinAndSelect('servicio.cuestionarioPrograma', 'cp')
|
|
//.leftJoinAndSelect('servicio.cuestionarioAlumno', 'ca')
|
|
.select([
|
|
'servicio.idServicio',
|
|
'servicio.fechaInicio',
|
|
'servicio.fechaFin',
|
|
'servicio.createdAt',
|
|
'servicio.updatedAt',
|
|
'usuario.idUsuario',
|
|
'usuario.usuario',
|
|
'usuario.nombre',
|
|
'carrera.idCarrera',
|
|
'carrera.carrera',
|
|
'status.idStatus',
|
|
'status.status',
|
|
// 'ca2.idCuestionarioAlumno2',
|
|
// 'ca.idCuestionarioAlumno',
|
|
// 'cp2.idCuestionarioPrograma2',
|
|
// 'cp.idCuestionarioPrograma'
|
|
])
|
|
.orderBy('servicio.updatedAt', 'DESC')
|
|
.skip(limite * (pagina - 1))
|
|
.take(limite);
|
|
|
|
if (whereStatus?.idStatus) {
|
|
query.andWhere('status.idStatus = :status', {
|
|
status: whereStatus.idStatus,
|
|
});
|
|
}
|
|
|
|
if (nombre) {
|
|
query.andWhere('usuario.nombre LIKE :nombre', { nombre: `%${nombre}%` });
|
|
}
|
|
|
|
if (numeroCuenta) {
|
|
query.andWhere('usuario.usuario LIKE :numeroCuenta', {
|
|
numeroCuenta: `%${numeroCuenta}%`,
|
|
});
|
|
}
|
|
|
|
const [servicios, count] = await query.getManyAndCount();
|
|
|
|
return {
|
|
count,
|
|
serviciosAdmin: servicios,
|
|
paginacion: {
|
|
pagina,
|
|
limite,
|
|
total: count,
|
|
paginas: Math.ceil(count / limite),
|
|
},
|
|
};
|
|
}
|
|
|
|
async obtenerServiciosResponsable(dto: ServiciosResponsableDto) {
|
|
const {
|
|
idUsuario,
|
|
idStatus,
|
|
nombre = '',
|
|
numeroCuenta = '',
|
|
pagina = 1,
|
|
} = dto;
|
|
|
|
// 1️⃣ Validar que el usuario exista y sea responsable
|
|
const responsable = await this.usuarioRepo.findOne({
|
|
where: { idUsuario },
|
|
relations: ['tipoUsuario'],
|
|
});
|
|
if (!responsable) throw new NotFoundException('No existe este usuario.');
|
|
if (responsable.tipoUsuario.idTipoUsuario !== 2)
|
|
throw new BadRequestException('No es un usuario tipo responsable.');
|
|
|
|
// 2️⃣ Crear el query builder
|
|
const query = this.servicioRepo
|
|
.createQueryBuilder('servicio')
|
|
.innerJoinAndSelect('servicio.usuario', 'usuario')
|
|
.leftJoinAndSelect('usuario.tipoUsuario', 'tipoUsuario')
|
|
.leftJoinAndSelect('servicio.cuestionarioPrograma2', 'cuestionarioPrograma2') // Agregue esta linea para tener la relacion y poder jalar la infromacion
|
|
.innerJoinAndSelect('servicio.programa', 'programa')
|
|
.innerJoinAndSelect('servicio.carrera', 'carrera')
|
|
.innerJoinAndSelect('servicio.status', 'status')
|
|
.where('programa.idUsuario = :idUsuario', { idUsuario })
|
|
.andWhere('usuario.usuario LIKE :numeroCuenta', {
|
|
numeroCuenta: `%${numeroCuenta}%`,
|
|
})
|
|
.andWhere('usuario.nombre LIKE :nombre', { nombre: `%${nombre}%` });
|
|
|
|
// 3️⃣ Filtro de estatus
|
|
if (idStatus) {
|
|
query.andWhere('status.idStatus = :idStatus', { idStatus });
|
|
} else {
|
|
query.andWhere('status.idStatus != :status', { status: 10 });
|
|
}
|
|
|
|
// 4️⃣ Orden, paginación y selección de campos
|
|
query
|
|
.select([
|
|
'servicio.idServicio',
|
|
'servicio.fechaInicio',
|
|
'servicio.fechaFin',
|
|
'servicio.cartaTermino',
|
|
'servicio.createdAt',
|
|
'servicio.idCuestionarioPrograma',
|
|
'servicio.idCuestionarioPrograma2',
|
|
'usuario.idUsuario',
|
|
'usuario.usuario',
|
|
'usuario.nombre',
|
|
'carrera.idCarrera',
|
|
'carrera.carrera',
|
|
'status.idStatus',
|
|
'status.status',
|
|
'cuestionarioPrograma2.idCuestionarioPrograma2', // Agrgue esta linea para tener la infromacion de la ralacion
|
|
])
|
|
.orderBy('servicio.createdAt', 'DESC') // Cambiamos el orderBy anteriormente orderBy('servicio.updatedAt', 'DESC')
|
|
.skip(25 * (pagina - 1))
|
|
.take(25);
|
|
|
|
// 5️⃣ Ejecutar y obtener datos + total
|
|
const [rows, count] = await query.getManyAndCount();
|
|
|
|
// Agregue una validacion para el cuestionario de responsable
|
|
const serviciosResponsable = rows.map((servicio) => ({
|
|
...servicio,
|
|
cuestionarioCompletado: Boolean(servicio.cuestionarioPrograma2),
|
|
}));
|
|
|
|
// Agregamos temporalmente para verificar que funcione
|
|
console.log(
|
|
serviciosResponsable.map(s => ({
|
|
idServicio: s.idServicio,
|
|
cuestionarioCompleto: s.cuestionarioCompletado,
|
|
}))
|
|
)
|
|
|
|
// 6️⃣ Retornar resultado en el mismo formato que antes
|
|
// return { count, serviciosResponsable: rows };
|
|
return { count, serviciosResponsable };
|
|
}
|
|
|
|
async update(
|
|
body: UpdateServicioDto,
|
|
files: Record<string, Express.Multer.File[]>,
|
|
) {
|
|
const idServicio = body.idServicio;
|
|
|
|
const servicio = await this.servicioRepo.findOne({ where: { idServicio }, relations: ['status'] });
|
|
if (!servicio)
|
|
throw new NotFoundException(
|
|
'Este Servicio Social no existe en la base de datos.',
|
|
);
|
|
|
|
let dataUpdate: Partial<Servicio> = {};
|
|
|
|
|
|
try {
|
|
if (files?.['cartaAceptacion']?.[0]?.filename) {
|
|
{
|
|
const result = await this.driveService.uploadFile(
|
|
`./server/uploads/${files['cartaAceptacion'][0].filename}`,
|
|
`Carta_Aceptacion.pdf`,
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
dataUpdate.cartaAceptacion = result === null ? undefined : result;
|
|
}
|
|
|
|
if (servicio.status.idStatus === 7) {
|
|
dataUpdate.status = { idStatus: 1 } as any;
|
|
}
|
|
}
|
|
} catch (err) { }
|
|
|
|
try {
|
|
if (files?.['cartaTermino']?.[0]?.filename) {
|
|
{
|
|
const result = await this.driveService.uploadFile(
|
|
`./server/uploads/${files['cartaTermino'][0].filename}`,
|
|
`Carta_Termino.pdf`,
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
dataUpdate.cartaTermino = result === null ? undefined : result;
|
|
}
|
|
}
|
|
} catch (err) { }
|
|
|
|
try {
|
|
if (files?.['informeGlobal']?.[0]?.filename) {
|
|
const result = await this.driveService.uploadFile(
|
|
`./server/uploads/${files['informeGlobal'][0].filename}`,
|
|
`Informe_Global.pdf`,
|
|
'application/pdf',
|
|
servicio.carpeta,
|
|
);
|
|
dataUpdate.informeGlobal = result === null ? undefined : result;
|
|
}
|
|
} catch (err) { }
|
|
|
|
|
|
if (body.correo) dataUpdate.correo = body.correo;
|
|
if (body.direccion)
|
|
dataUpdate.direccion = this.validacionService.validarAlfanumerico(
|
|
body.direccion,
|
|
'dirección',
|
|
false,
|
|
200,
|
|
);
|
|
if (body.telefono)
|
|
dataUpdate.telefono = this.validacionService.validarNumero(
|
|
body.telefono,
|
|
'teléfono',
|
|
true,
|
|
15,
|
|
);
|
|
|
|
if (body.fechaInicio) dataUpdate.fechaInicio = moment(body.fechaInicio).format('YYYY-MM-DD');
|
|
if (body.fechaFin) dataUpdate.fechaFin = moment(body.fechaFin).format('YYYY-MM-DD');
|
|
if (body.fechaNacimiento) dataUpdate.fechaNacimiento = moment(body.fechaNacimiento).format('YYYY-MM-DD');
|
|
|
|
if (this.validacionService.validarObjetoVacio(dataUpdate)) {
|
|
throw new BadRequestException(
|
|
'No se envió nada para actualizar este Servicio Social.',
|
|
);
|
|
}
|
|
|
|
|
|
await this.servicioRepo
|
|
.createQueryBuilder()
|
|
.update(Servicio)
|
|
.set(dataUpdate)
|
|
.where('idServicio = :idServicio', { idServicio })
|
|
.execute();
|
|
|
|
|
|
if (dataUpdate.cartaTermino || dataUpdate.informeGlobal) {
|
|
await this.validacionService.validarPreTermino(idServicio);
|
|
}
|
|
|
|
return {
|
|
message: 'Se guardaron correctamente los cambios de este servicio.',
|
|
};
|
|
}
|
|
|
|
async obtenerTodosLosServicios() {
|
|
return await this.servicioRepo.find({
|
|
relations: ['usuario', 'carrera', 'status', 'programa'],
|
|
take: 10,
|
|
order: {
|
|
idServicio: 'DESC', // Ordenar por el más reciente primero
|
|
},
|
|
});
|
|
}
|
|
@Cron('*/5 * * * *')
|
|
async diario(): Promise<void> {
|
|
const now = moment().startOf('day');
|
|
let mensaje = '';
|
|
|
|
const servicios = await this.servicioRepo.find({
|
|
where: { idServicio: In([19067, 19070]), status: { idStatus: 3 } },
|
|
relations: [
|
|
'status',
|
|
'usuario',
|
|
'programa',
|
|
'programa.usuario',
|
|
],
|
|
});
|
|
|
|
for (const servicio of servicios) {
|
|
const fechaFin = moment(servicio.fechaFin).startOf('day');
|
|
|
|
const diferencia = fechaFin.diff(now, 'days');
|
|
|
|
console.log("diferencia:", diferencia)
|
|
|
|
// ===== 7 días antes =====
|
|
if (diferencia === 7) {
|
|
const correoAlumno = avisoTerminoAlumno(
|
|
servicio.usuario.nombre,
|
|
);
|
|
|
|
const correoResponsable = avisoTerminoResponsable(
|
|
servicio.usuario.nombre,
|
|
);
|
|
|
|
mensaje +=
|
|
`Se envió correo al alumno ${servicio.usuario.usuario} ` +
|
|
`con id ${servicio.usuario.idUsuario} al correo ${servicio.correo} ` +
|
|
`y al responsable ${servicio.programa.usuario.nombre} ` +
|
|
`con id ${servicio.programa.usuario.idUsuario} ` +
|
|
`y correo ${servicio.programa.usuario.usuario}\n\n`;
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoAlumno.subject,
|
|
to: servicio.correo,
|
|
text: correoAlumno.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
|
|
await this.gmailService.enviarCorreo({
|
|
subject: correoResponsable.subject,
|
|
to: servicio.programa.usuario.usuario,
|
|
text: correoResponsable.msj,
|
|
fecha_recibido: new Date(),
|
|
});
|
|
}
|
|
|
|
// ===== Servicio vencido =====
|
|
else if (diferencia <= 0) {
|
|
mensaje +=
|
|
`El servicio con id ${servicio.idServicio} ` +
|
|
`del alumno ${servicio.usuario.usuario} ` +
|
|
`con id ${servicio.usuario.idUsuario} ` +
|
|
`pasó al status 4\n\n`;
|
|
|
|
await this.servicioRepo.update(
|
|
{ idServicio: servicio.idServicio },
|
|
{ status: { idStatus: 4 } },
|
|
);
|
|
}
|
|
}
|
|
|
|
// ===== Reporte =====
|
|
console.log("se realizo carga masiva")
|
|
}
|
|
}
|