Se agregaron validaciones
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
API_PORT = 4000
|
||||
JWT_SECRET = "your_jwt_secret"
|
||||
JWT_EXPIRES_IN = "1h"
|
||||
DB_HOST = localhost
|
||||
DB_PORT = 32769
|
||||
DB_USER = root
|
||||
DB_PASS = root
|
||||
DB_NAME = carga_test
|
||||
DB_SYNC = true
|
||||
//api
|
||||
API_URL = //URL web service
|
||||
|
||||
|
||||
//Gmail configuration, llaves de acceso
|
||||
EMAIL_USER =
|
||||
CLIENT_ID =
|
||||
CLIENT_SECRET =
|
||||
REFRESH_TOKEN =
|
||||
Generated
+52
@@ -15,6 +15,7 @@
|
||||
"@nestjs/jwt": "^11.0.0",
|
||||
"@nestjs/passport": "^11.0.5",
|
||||
"@nestjs/platform-express": "^11.1.3",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
@@ -24,6 +25,7 @@
|
||||
"exceljs": "^4.4.0",
|
||||
"multer": "^2.0.1",
|
||||
"mysql2": "^3.14.1",
|
||||
"nodemailer": "^7.0.3",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
@@ -2657,6 +2659,19 @@
|
||||
"@nestjs/core": "^11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/schedule": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-6.0.0.tgz",
|
||||
"integrity": "sha512-aQySMw6tw2nhitELXd3EiRacQRgzUKD9mFcUZVOJ7jPLqIBvXOyvRWLsK9SdurGA+jjziAlMef7iB5ZEFFoQpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron": "4.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/schematics": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.5.tgz",
|
||||
@@ -3566,6 +3581,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz",
|
||||
"integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/methods": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
|
||||
@@ -6158,6 +6179,19 @@
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.0.tgz",
|
||||
"integrity": "sha512-ciiYNLfSlF9MrDqnbMdRWFiA6oizSF7kA1osPP9lRzNu0Uu+AWog1UKy7SkckiDY2irrNjeO6qLyKnXC8oxmrw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/luxon": "~3.6.0",
|
||||
"luxon": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -9504,6 +9538,15 @@
|
||||
"url": "https://github.com/sponsors/wellwelwel"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
|
||||
"integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.17",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||
@@ -9935,6 +9978,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz",
|
||||
"integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"@nestjs/jwt": "^11.0.0",
|
||||
"@nestjs/passport": "^11.0.5",
|
||||
"@nestjs/platform-express": "^11.1.3",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
@@ -35,6 +36,7 @@
|
||||
"exceljs": "^4.4.0",
|
||||
"multer": "^2.0.1",
|
||||
"mysql2": "^3.14.1",
|
||||
"nodemailer": "^7.0.3",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
|
||||
+9
-2
@@ -10,10 +10,14 @@ import { ExcelModule } from './excel/excel.module';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { MovimientoModule } from './movimiento/movimiento.module';
|
||||
import { UsuariosModule } from './usuarios/usuarios.module';
|
||||
import { MailService } from './mail/mail.service';
|
||||
import { MailModule } from './mail/mail.module';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ScheduleModule.forRoot(),
|
||||
ConfigModule.forRoot({ isGlobal: true }),
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
@@ -27,6 +31,7 @@ import { UsuariosModule } from './usuarios/usuarios.module';
|
||||
// no prints en claro en prod:
|
||||
password: config.get('DB_PASS', ''),
|
||||
database: config.get('DB_NAME', 'test'),
|
||||
dropSchema: false, // solo para desarrollo
|
||||
};
|
||||
Logger.log('[DB CONFIG] ' + JSON.stringify({
|
||||
...dbConfig,
|
||||
@@ -39,9 +44,10 @@ import { UsuariosModule } from './usuarios/usuarios.module';
|
||||
|
||||
logging: ['error', 'warn', 'info', 'query', 'schema'],
|
||||
logger: 'advanced-console',
|
||||
|
||||
retryAttempts: 5,
|
||||
retryDelay: 2000,
|
||||
dropSchema: false, // solo para desarrollo
|
||||
|
||||
};
|
||||
},
|
||||
}),
|
||||
@@ -51,7 +57,8 @@ import { UsuariosModule } from './usuarios/usuarios.module';
|
||||
ExcelModule,
|
||||
AuthModule,
|
||||
MovimientoModule,
|
||||
UsuariosModule
|
||||
UsuariosModule,
|
||||
MailModule
|
||||
|
||||
],
|
||||
controllers: [AppController],
|
||||
|
||||
@@ -88,7 +88,6 @@ export class Usuario {
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 9,
|
||||
unique: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// src/excel/excel.controller.ts
|
||||
import { Controller, Post, Get, UseGuards, Request, Res, UploadedFile, UseInterceptors, HttpStatus, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import { Controller, Post, Get, UseGuards, Request, Res, UploadedFile, UseInterceptors, HttpStatus, Param, ParseIntPipe, Body, BadRequestException } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
@@ -7,6 +7,10 @@ import { Response } from 'express';
|
||||
import { ExcelDocumentation } from './excel.documentation';
|
||||
import { ExcelService } from './excel.service';
|
||||
import { MovimientoService } from '../movimiento/movimiento.service';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto';
|
||||
import { Origen } from 'src/entities/entities';
|
||||
import { UsuariosService } from 'src/usuarios/usuarios.service';
|
||||
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
@ApiBearerAuth('bearer')
|
||||
@@ -15,8 +19,35 @@ export class ExcelController {
|
||||
constructor(
|
||||
private readonly excelService: ExcelService,
|
||||
private readonly movimientoService: MovimientoService,
|
||||
private readonly mailService: MailService,
|
||||
private readonly usuarioService: UsuariosService // Asegúrate de importar el servicio de correo
|
||||
) { }
|
||||
|
||||
|
||||
@Post('carga')
|
||||
async cargaUsuario(@Request() req, @Body() usuario: CreateUsuarioDto) {
|
||||
console.log('Usuario recibido:', usuario);
|
||||
if (req.user.origen != 'LOAD') {
|
||||
throw new BadRequestException('Origen no permitido para carga')
|
||||
}
|
||||
const alta = await this.usuarioService.cargaIndividual(usuario, req.user.origen)
|
||||
console.log('Alta de usuario:', alta);
|
||||
await this.movimientoService.updateStatus(alta.movId, 'SUCCESS')
|
||||
|
||||
this.mailService.sendMail({
|
||||
to: req.user.email, // Asegúrate de que el usuario tenga un email
|
||||
subject: 'Carga de datos exitosa',
|
||||
text: "La carga de datos se ha realizado con éxito.",
|
||||
html: `<p>La carga de datos se ha realizado con éxito. ` + alta,
|
||||
});
|
||||
|
||||
await this.excelService.enviarCargaMasiva();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Post('verify')
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
@ExcelDocumentation.verifyExcel()
|
||||
@@ -40,7 +71,7 @@ export class ExcelController {
|
||||
const origen = req.user.origen; // ahora sí existe
|
||||
if (origen != 'LOAD') {
|
||||
await this.movimientoService.log(
|
||||
'LOAD',
|
||||
origen,
|
||||
'FAILED',
|
||||
'Origen no permitido para carga'
|
||||
);
|
||||
@@ -50,13 +81,46 @@ export class ExcelController {
|
||||
const result = await this.excelService.loadFile(file.buffer);
|
||||
//Actualizar el estado de los movimientos
|
||||
if (!result) {
|
||||
this.mailService.sendMail({
|
||||
to: req.user.email, // Asegúrate de que el usuario tenga un email
|
||||
subject: 'Carga de datos Fallida',
|
||||
text: "No se pudieron subir datos.",
|
||||
html: '<p>No se pudieron subir datos.</p>',
|
||||
});
|
||||
throw new Error('No se pudo procesar el archivo.');
|
||||
}
|
||||
|
||||
if (result.inserted == 0) {
|
||||
this.mailService.sendMail({
|
||||
to: req.user.email, // Asegúrate de que el usuario tenga un email
|
||||
subject: 'Carga de datos Fallida',
|
||||
text: "No se pudieron subir datos.",
|
||||
html: `<p> Se han insertado ${result.inserted} registros.</p>
|
||||
<p>Errores encontrados:</p>
|
||||
<ul>${result.errors.map(error => `<li>${error}</li>`).join('')}</ul>`,
|
||||
});
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
await this.movimientoService.updateStatus(
|
||||
result.id_movimiento,
|
||||
'SUCCESS',
|
||||
`inserted=${result.inserted}`
|
||||
);
|
||||
|
||||
this.mailService.sendMail({
|
||||
to: req.user.email, // Asegúrate de que el usuario tenga un email
|
||||
subject: 'Carga de datos exitosa',
|
||||
text: "La carga de datos se ha realizado con éxito.",
|
||||
html: `<p>La carga de datos se ha realizado con éxito. Se han insertado ${result.inserted} registros.</p>
|
||||
<p>Errores encontrados:</p>
|
||||
<ul>${result.errors.map(error => `<li>${error}</li>`).join('')}</ul>`,
|
||||
});
|
||||
|
||||
await this.excelService.enviarCargaMasiva();
|
||||
|
||||
|
||||
return result
|
||||
|
||||
} catch (err) {
|
||||
@@ -196,8 +260,9 @@ export class ExcelController {
|
||||
|
||||
//Agregarlo en su propio controller
|
||||
@Get('movimientos')
|
||||
async getMovimientos() {
|
||||
const movimientos = await this.movimientoService.findAll();
|
||||
async getMovimientos(@Request() req) {
|
||||
|
||||
const movimientos = await this.movimientoService.findAll(req.user.origen);
|
||||
return movimientos;
|
||||
}
|
||||
|
||||
@@ -217,4 +282,15 @@ export class ExcelController {
|
||||
return { message: 'Servicios activados correctamente' };
|
||||
}
|
||||
|
||||
|
||||
@Get('cargaIndividual')
|
||||
async cargarIndividual(
|
||||
@Request() req) {
|
||||
const origen = req.user.origen; // ahora sí existe
|
||||
return this.movimientoService.findAllCargaIndv(origen);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -2,17 +2,21 @@ import { Module } from '@nestjs/common';
|
||||
import { ExcelService } from './excel.service';
|
||||
import { ExcelController } from './excel.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario } from '../entities/entities';
|
||||
import { Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario, UsuariosDelSistema } from '../entities/entities';
|
||||
import { MovimientoModule } from 'src/movimiento/movimiento.module';
|
||||
import { ServActivos } from 'src/usuarios/entities/servActivos.entitie';
|
||||
import { MailModule } from 'src/mail/mail.module';
|
||||
import { UsuariosService } from 'src/usuarios/usuarios.service';
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario, ServActivos]),
|
||||
MovimientoModule
|
||||
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, UsuarioTipoUsuario, TipoUsuario, ServActivos, UsuariosDelSistema]),
|
||||
MovimientoModule,
|
||||
MailModule,
|
||||
|
||||
],
|
||||
providers: [ExcelService],
|
||||
providers: [ExcelService, UsuariosService],
|
||||
controllers: [ExcelController],
|
||||
})
|
||||
export class ExcelModule { }
|
||||
|
||||
+130
-5
@@ -3,11 +3,12 @@ import { Injectable, BadRequestException, Logger } from '@nestjs/common';
|
||||
import { Workbook } from 'exceljs';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { CarreraUsuario, TipoUsuario, Usuario, UsuarioTipoUsuario } from '../entities/entities';
|
||||
import { CarreraUsuario, TipoUsuario, Usuario, UsuariosDelSistema, 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';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
|
||||
export interface UsuarioRow {
|
||||
cuenta: string;
|
||||
@@ -44,7 +45,10 @@ export class ExcelService {
|
||||
private readonly tipoUsuarioRepo: Repository<TipoUsuario>,
|
||||
@InjectRepository(ServActivos)
|
||||
private readonly servActivosRepo: Repository<ServActivos>,
|
||||
@InjectRepository(UsuariosDelSistema)
|
||||
private readonly usuariosDelSistemaRepo: Repository<UsuariosDelSistema>,
|
||||
private readonly movimientoService: MovimientoService,
|
||||
private readonly mailService: MailService
|
||||
|
||||
// … inyecta otros repositorios si los usarás
|
||||
) { }
|
||||
@@ -197,17 +201,24 @@ export class ExcelService {
|
||||
const status = this.validateRows(file);
|
||||
const errs = status.errors;
|
||||
const rows = status.rowsGood;
|
||||
let carga
|
||||
if (rows.length == 0) {
|
||||
throw new BadRequestException('No se encontraron filas válidas para cargar. ' + errs);
|
||||
}
|
||||
|
||||
|
||||
const movimiento = await this.movimientoService.log(
|
||||
|
||||
'LOAD',
|
||||
'LOADING',
|
||||
undefined
|
||||
undefined,
|
||||
`CARGA MASIVA DE USUARIOS`,
|
||||
true, // flag para indicar que es una carga masiva
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
let contador: number = 0;
|
||||
|
||||
for (const r of rows) {
|
||||
//0.1
|
||||
@@ -217,6 +228,7 @@ export class ExcelService {
|
||||
|
||||
if (userExists) {
|
||||
errs.push(`Cuenta ${r.cuenta} ya existe, se omite.`);
|
||||
contador++;
|
||||
continue; // si ya existe, no lo insertamos
|
||||
}
|
||||
|
||||
@@ -290,7 +302,71 @@ export class ExcelService {
|
||||
// 6) ServActivos (si es necesario)
|
||||
switch (r.tipo.trim()) {
|
||||
|
||||
case 'Diplomado':
|
||||
const servActivosDiplomado = this.servActivosRepo.create({
|
||||
Correo: true,
|
||||
usuario: user,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await this.servActivosRepo.save(servActivosDiplomado);
|
||||
|
||||
break;
|
||||
|
||||
case 'Extra Largo':
|
||||
const servActivosExtraLargo = this.servActivosRepo.create({
|
||||
Prestamos: true,
|
||||
Correo: true,
|
||||
usuario: user,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await this.servActivosRepo.save(servActivosExtraLargo);
|
||||
break;
|
||||
|
||||
case 'Servicio Social':
|
||||
const servActivosServicio = this.servActivosRepo.create({
|
||||
Red: true,
|
||||
AT: true,
|
||||
Correo: true,
|
||||
usuario: user,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await this.servActivosRepo.save(servActivosServicio);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 'Idiomas R (UNAM)':
|
||||
case 'Idiomas Sabatino':
|
||||
const servActivosIdiomas = this.servActivosRepo.create({
|
||||
Red: true,
|
||||
Correo: true,
|
||||
usuario: user,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await this.servActivosRepo.save(servActivosIdiomas);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
case 'Reinscrito':
|
||||
case 'Posgrado':
|
||||
case 'Intercambio UNAM':
|
||||
case 'Movilidad':
|
||||
case 'Ampliación de Conocimiento':
|
||||
case 'Licenciatura':
|
||||
case 'Profesor':
|
||||
const servActivos = this.servActivosRepo.create({
|
||||
@@ -324,7 +400,10 @@ export class ExcelService {
|
||||
|
||||
|
||||
}
|
||||
return { inserted: rows.length, id_movimiento: movimiento.id_mov, errors: errs };
|
||||
|
||||
|
||||
|
||||
return { inserted: rows.length - contador, id_movimiento: movimiento.id_mov, errors: errs };
|
||||
}
|
||||
|
||||
|
||||
@@ -558,7 +637,8 @@ export class ExcelService {
|
||||
}).join('\n');
|
||||
|
||||
const tablaCompleta = header + rows;
|
||||
|
||||
console.log(tablaCompleta);
|
||||
console.log('Usuarios encontrados:', usuarios);
|
||||
return tablaCompleta;
|
||||
}
|
||||
|
||||
@@ -586,6 +666,7 @@ export class ExcelService {
|
||||
},
|
||||
servActivo: {
|
||||
ATStatus: 'Inactivo',
|
||||
AT: true
|
||||
},
|
||||
},
|
||||
relations: [
|
||||
@@ -674,6 +755,50 @@ export class ExcelService {
|
||||
|
||||
}
|
||||
|
||||
async enviarCargaMasiva(): Promise<void> {
|
||||
const usuarios_red = await this.usuariosDelSistemaRepo.findOne({ where: { origen: { origen: 'RED' } } });
|
||||
const usuarios_at = await this.usuariosDelSistemaRepo.findOne({ where: { origen: { origen: 'AT' } } });
|
||||
const usuarios_correo = await this.usuariosDelSistemaRepo.findOne({ where: { origen: { origen: 'CORREO' } } });
|
||||
const usuarios_solicita = await this.usuariosDelSistemaRepo.findOne({ where: { origen: { origen: 'SOLICITA' } } });
|
||||
if (!usuarios_red || !usuarios_at || !usuarios_correo || !usuarios_solicita) {
|
||||
throw new BadRequestException('No se encontraron usuarios para enviar correo');
|
||||
}
|
||||
|
||||
// Aquí puedes enviar el correo usando MailService
|
||||
await this.mailService.sendMail({
|
||||
to: usuarios_red.correo ?? '',
|
||||
subject: 'Carga de Usuarios',
|
||||
text: 'Se ha realizado una carga de usuarios en el sistema.',
|
||||
html: '',
|
||||
});
|
||||
await this.mailService.sendMail({
|
||||
to: usuarios_at.correo ?? '',
|
||||
subject: 'Carga de Usuarios',
|
||||
text: 'Se ha realizado una carga de usuarios en el sistema.',
|
||||
html: '',
|
||||
});
|
||||
await this.mailService.sendMail({
|
||||
to: usuarios_correo.correo ?? '',
|
||||
subject: 'Carga de Usuarios',
|
||||
text: 'Se ha realizado una carga de usuarios en el sistema.',
|
||||
html: '',
|
||||
});
|
||||
await this.mailService.sendMail({
|
||||
to: usuarios_solicita.correo ?? '',
|
||||
subject: 'Carga de Usuarios',
|
||||
text: 'Se ha realizado una carga de usuarios en el sistema.',
|
||||
html: '',
|
||||
});
|
||||
|
||||
|
||||
|
||||
console.log(`Correo enviados`);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { IsString, IsEmail, IsDate, IsOptional } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class SendCorreoDto {
|
||||
@IsEmail()
|
||||
to: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
subject: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
text: string;
|
||||
|
||||
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
html: string;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// src/excel/excel.controller.ts
|
||||
import { Controller, Post, Get, UseGuards, Request, Res, UploadedFile, UseInterceptors, HttpStatus, Param, ParseIntPipe, Body } from '@nestjs/common';
|
||||
import { SendCorreoDto } from './dto/send-email.dto';
|
||||
import { MailService } from './mail.service';
|
||||
|
||||
|
||||
@Controller('mail')
|
||||
export class MailController {
|
||||
constructor(
|
||||
private readonly mailService: MailService
|
||||
) { }
|
||||
|
||||
@Post('send')
|
||||
async sendMail(@Body() body: SendCorreoDto) {
|
||||
const result =
|
||||
await this.mailService.sendMail(body)
|
||||
.then((value) => {
|
||||
console.log("Se mandaron los correos", value);
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
|
||||
// sistem
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// src/movimiento/movimiento.module.ts
|
||||
import { Module } from '@nestjs/common';
|
||||
import { MailService } from './mail.service';
|
||||
import { MailController } from './mail.controller';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [MailController],
|
||||
providers: [MailService],
|
||||
exports: [MailService],
|
||||
})
|
||||
export class MailModule { }
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import { SendCorreoDto } from 'src/mail/dto/send-email.dto';
|
||||
|
||||
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
|
||||
async sendMail(sendEmail: SendCorreoDto) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
|
||||
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
type: 'OAuth2',
|
||||
user: process.env.EMAIL_USER, // tu correo de Gmail
|
||||
clientId: process.env.CLIENT_ID, // tu Client ID de OAuth2
|
||||
clientSecret: process.env.CLIENT_SECRET, // tu Client Secret de OAuth2
|
||||
refreshToken: process.env.REFRESH_TOKEN, // tu Refresh Token de OAuth2
|
||||
//accessToken: sistem.accessToken, // opcional
|
||||
},
|
||||
pool: true,
|
||||
maxConnections: 1,
|
||||
maxMessages: 100,
|
||||
rateDelta: 2000,
|
||||
rateLimit: 1
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const mailOptions = {
|
||||
from: process.env.EMAIL_USER, // tu correo de Gmail
|
||||
to: sendEmail.to,
|
||||
subject: sendEmail.subject,
|
||||
text: sendEmail.text,
|
||||
html: sendEmail.html,
|
||||
};
|
||||
|
||||
|
||||
console.log(mailOptions);
|
||||
|
||||
|
||||
|
||||
|
||||
let resMail = await transporter.sendMail(mailOptions);
|
||||
if (!resMail) throw new Error("")
|
||||
|
||||
|
||||
const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido";
|
||||
|
||||
|
||||
|
||||
if (!resMail) {
|
||||
throw new Error("fallo")
|
||||
}
|
||||
|
||||
|
||||
return (statusTexto);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { MovimientoService } from './movimiento.service';
|
||||
import { Movimiento, Origen } from '../entities/entities';
|
||||
import { Movimiento, Origen, Usuario } from '../entities/entities';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Movimiento, Origen])],
|
||||
imports: [TypeOrmModule.forFeature([Movimiento, Origen, Usuario])],
|
||||
providers: [MovimientoService],
|
||||
exports: [MovimientoService],
|
||||
})
|
||||
export class MovimientoModule {}
|
||||
export class MovimientoModule { }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Movimiento } from '../entities/entities';
|
||||
import { QueryRunner, Repository } from 'typeorm';
|
||||
import { Movimiento, Usuario } from '../entities/entities';
|
||||
import { Origen } from '../entities/entities';
|
||||
|
||||
@Injectable()
|
||||
@@ -11,6 +11,8 @@ export class MovimientoService {
|
||||
private readonly movRepo: Repository<Movimiento>,
|
||||
@InjectRepository(Origen)
|
||||
private readonly origenRepo: Repository<Origen>,
|
||||
@InjectRepository(Usuario)
|
||||
private readonly usuarioRepo: Repository<Usuario>,
|
||||
) { }
|
||||
|
||||
/** Crea un registro de movimiento */
|
||||
@@ -23,7 +25,14 @@ export class MovimientoService {
|
||||
): Promise<Movimiento> {
|
||||
// 1) Obtén el origen o falla si no existe
|
||||
const origin = await this.origenRepo.findOne({ where: { origen } });
|
||||
if (!origin) throw new Error(`Origen desconocido: ${origen}`);
|
||||
let origenRepo = origin;
|
||||
if (!origin) {
|
||||
const newOrigin = this.origenRepo.create({ origen });
|
||||
origenRepo = await this.origenRepo.save(newOrigin);
|
||||
}
|
||||
if (!origenRepo) {
|
||||
throw new Error(`No se pudo obtener o crear el origen: ${origen}`);
|
||||
}
|
||||
|
||||
// 2) Crea el objeto movimiento
|
||||
const movimiento = this.movRepo.create({
|
||||
@@ -32,7 +41,7 @@ export class MovimientoService {
|
||||
observaciones,
|
||||
reporte,
|
||||
flag,
|
||||
origen: { id_origen: origin.id_origen },
|
||||
origen: { id_origen: origenRepo.id_origen },
|
||||
});
|
||||
|
||||
// 3) Guarda y devuelve el ID
|
||||
@@ -40,6 +49,35 @@ export class MovimientoService {
|
||||
return saved;
|
||||
}
|
||||
|
||||
async logger(
|
||||
queryRunner: QueryRunner,
|
||||
origenNombre: string,
|
||||
status: string,
|
||||
reporte: string | undefined,
|
||||
observaciones: string
|
||||
): Promise<Movimiento> {
|
||||
const origenEntidad = await queryRunner.manager.findOne(Origen, {
|
||||
where: { origen: origenNombre },
|
||||
});
|
||||
|
||||
if (!origenEntidad) {
|
||||
throw new Error(`Origen no encontrado: ${origenNombre}`);
|
||||
}
|
||||
|
||||
const nuevoMov = queryRunner.manager.create(Movimiento, {
|
||||
fecha_mov: new Date(),
|
||||
status,
|
||||
observaciones,
|
||||
reporte,
|
||||
origen: origenEntidad,
|
||||
flag: false,
|
||||
});
|
||||
|
||||
return await queryRunner.manager.save(nuevoMov);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Actualiza el status de un movimiento existente */
|
||||
async updateStatus(id_movimiento: number, nuevoStatus: string, observaciones?: string): Promise<void> {
|
||||
@@ -56,8 +94,149 @@ export class MovimientoService {
|
||||
await this.movRepo.save(movimiento);
|
||||
}
|
||||
|
||||
async findAll(): Promise<Movimiento[]> {
|
||||
return await this.movRepo.find({ where: { origen: { origen: 'LOAD' } } });
|
||||
async findAll(origen: string): Promise<{ move: any[]; button: boolean }> {
|
||||
const statusFieldMap = {
|
||||
AT: 'ATStatus',
|
||||
RED: 'RedStatus',
|
||||
CORREO: 'CorreoStatus',
|
||||
SOLICITA: 'PrestamosStatus',
|
||||
} as const;
|
||||
|
||||
const FieldMap = {
|
||||
AT: 'AT',
|
||||
RED: 'Red',
|
||||
CORREO: 'Correo',
|
||||
SOLICITA: 'Prestamos',
|
||||
} as const;
|
||||
|
||||
|
||||
|
||||
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
||||
|
||||
if (!field) {
|
||||
const movimientos = await this.movRepo.find({
|
||||
where: {
|
||||
origen: { origen: 'LOAD' },
|
||||
status: 'SUCCESS',
|
||||
reporte: 'CARGA MASIVA DE USUARIOS',
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
const mov = await this.movRepo.find({
|
||||
where: {
|
||||
origen: { origen: 'SISTEMA' },
|
||||
status: 'SUCCESS',
|
||||
reporte: 'CARGA MASIVA WEB SERVICE',
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
const mov2 = await this.movRepo.find({
|
||||
where: {
|
||||
|
||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||
status: 'SUCCESS',
|
||||
|
||||
|
||||
},
|
||||
});
|
||||
console.log('movimientos:', mov2)
|
||||
|
||||
|
||||
|
||||
|
||||
const todosLosMovimientos = [...movimientos, ...mov, ...mov2];
|
||||
console.log(todosLosMovimientos)
|
||||
return { move: todosLosMovimientos, button: false };
|
||||
}
|
||||
|
||||
const movimientos = await this.movRepo.find({
|
||||
where: {
|
||||
origen: { origen: 'LOAD' },
|
||||
reporte: 'CARGA MASIVA DE USUARIOS',
|
||||
status: 'SUCCESS',
|
||||
usuario: {
|
||||
servActivo: {
|
||||
[field]: 'Inactivo'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const mov = await this.movRepo.find({
|
||||
where: {
|
||||
origen: { origen: 'SISTEMA' },
|
||||
reporte: 'CARGA MASIVA WEB SERVICE',
|
||||
status: 'SUCCESS',
|
||||
usuario: {
|
||||
servActivo: {
|
||||
[field]: 'Inactivo'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const mov2 = await this.movRepo.find({
|
||||
where: {
|
||||
|
||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||
status: 'SUCCESS',
|
||||
usuario: {
|
||||
servActivo: {
|
||||
[field]: 'Inactivo'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const todosLosMovimientos = [...movimientos, ...mov, ...mov2];
|
||||
console.log(todosLosMovimientos, movimientos)
|
||||
return { move: todosLosMovimientos, button: true };
|
||||
}
|
||||
|
||||
async findAllCargaIndv(origen): Promise<Usuario[]> {
|
||||
|
||||
const statusFieldMap = {
|
||||
AT: 'ATStatus',
|
||||
RED: 'RedStatus',
|
||||
CORREO: 'CorreoStatus',
|
||||
SOLICITA: 'PrestamosStatus',
|
||||
} as const;
|
||||
|
||||
const FieldMap = {
|
||||
AT: 'AT',
|
||||
RED: 'Red',
|
||||
CORREO: 'Correo',
|
||||
SOLICITA: 'Prestamos',
|
||||
} as const;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
||||
|
||||
const origenField = FieldMap[origen as keyof typeof FieldMap];
|
||||
|
||||
if (!field) {
|
||||
throw new Error(`Origen desconocido: ${origen}`);
|
||||
}
|
||||
|
||||
const usuarios = await this.usuarioRepo.find({
|
||||
where: {
|
||||
movimiento: {
|
||||
|
||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||
},
|
||||
|
||||
servActivo: {
|
||||
[field]: 'Inactivo',
|
||||
[origenField]: true,
|
||||
},
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
return usuarios;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,46 @@
|
||||
export class CreateUsuarioDto {}
|
||||
import { IsNumber, IsOptional, IsString, Length } from "class-validator";
|
||||
|
||||
export class CreateUsuarioDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
num_cuenta?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
carrera?: string;
|
||||
|
||||
|
||||
@IsString()
|
||||
tipo_usuario: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
clave_carrera?: string;
|
||||
|
||||
@IsString()
|
||||
nombre: string;
|
||||
|
||||
@IsString()
|
||||
a_paterno: string;
|
||||
|
||||
@IsString()
|
||||
a_materno: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Length(10, 13)
|
||||
rfc?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Length(8, 8)
|
||||
fecha_nacimiento?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
generacion?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
genero?: string;
|
||||
}
|
||||
@@ -11,11 +11,18 @@ export class UsuariosController {
|
||||
constructor(private readonly usuariosService: UsuariosService) { }
|
||||
|
||||
|
||||
@Get('users')
|
||||
finsdAll() {
|
||||
return this.usuariosService.enviarSolicitud();
|
||||
}
|
||||
|
||||
@Get(':noCuenta')
|
||||
findOne(@Param('noCuenta') noCuenta: string) {
|
||||
return this.usuariosService.findOneStatus(noCuenta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// @UseGuards(AuthGuard('jwt'))
|
||||
// @ApiBearerAuth('bearer')
|
||||
// @Post()
|
||||
|
||||
@@ -2,18 +2,20 @@ import { Module } from '@nestjs/common';
|
||||
import { UsuariosService } from './usuarios.service';
|
||||
import { UsuariosController } from './usuarios.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Carrera, CarreraUsuario, Genero, Usuario } from 'src/entities/entities';
|
||||
import { Carrera, CarreraUsuario, Genero, TipoUsuario, Usuario, UsuariosDelSistema, UsuarioTipoUsuario } from 'src/entities/entities';
|
||||
import { MovimientoModule } from 'src/movimiento/movimiento.module';
|
||||
import { ServActivos } from './entities/servActivos.entitie';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
import { ExcelService } from 'src/excel/excel.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, ServActivos]),
|
||||
TypeOrmModule.forFeature([Usuario, Genero, Carrera, CarreraUsuario, ServActivos, TipoUsuario, UsuarioTipoUsuario, UsuariosDelSistema]),
|
||||
MovimientoModule
|
||||
|
||||
],
|
||||
controllers: [UsuariosController],
|
||||
providers: [UsuariosService],
|
||||
providers: [UsuariosService, MailService, ExcelService],
|
||||
exports: [TypeOrmModule.forFeature([ServActivos])],
|
||||
})
|
||||
export class UsuariosModule { }
|
||||
|
||||
@@ -1,20 +1,42 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { CreateUsuarioDto } from './dto/create-usuario.dto';
|
||||
import { UpdateUsuarioDto } from './dto/update-usuario.dto';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { CarreraUsuario, Usuario } from 'src/entities/entities';
|
||||
import { Carrera, CarreraUsuario, Genero, TipoUsuario, Usuario, UsuarioTipoUsuario } from 'src/entities/entities';
|
||||
import { Repository } from 'typeorm';
|
||||
import { ServActivos } from './entities/servActivos.entitie';
|
||||
import { MovimientoService } from 'src/movimiento/movimiento.service';
|
||||
import { MailService } from 'src/mail/mail.service';
|
||||
import { error } from 'console';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { ExcelService } from 'src/excel/excel.service';
|
||||
|
||||
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class UsuariosService {
|
||||
private readonly logger = new Logger(UsuariosService.name);
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Usuario)
|
||||
private readonly usuarioRepository: Repository<Usuario>,
|
||||
@InjectRepository(CarreraUsuario)
|
||||
private readonly carreraUsuarioRepository: Repository<CarreraUsuario>,
|
||||
@InjectRepository(Carrera)
|
||||
private readonly carreraRepository: Repository<Carrera>,
|
||||
@InjectRepository(ServActivos)
|
||||
private readonly servActivosRepository: Repository<ServActivos>,
|
||||
@InjectRepository(TipoUsuario)
|
||||
private readonly tipoUsuarioRepository: Repository<TipoUsuario>,
|
||||
@InjectRepository(Genero)
|
||||
private readonly generoRepository: Repository<Genero>,
|
||||
@InjectRepository(CarreraUsuario)
|
||||
private readonly carreraUsuario: Repository<CarreraUsuario>,
|
||||
@InjectRepository(UsuarioTipoUsuario)
|
||||
private readonly usuarioTipoUsuario: Repository<UsuarioTipoUsuario>,
|
||||
private readonly movimientoService: MovimientoService,
|
||||
private readonly mailService: MailService,
|
||||
private readonly excelService: ExcelService, // Asegúrate de importar el servicio de Excel
|
||||
|
||||
) { }
|
||||
|
||||
altaIndividual(createUsuarioDto: CreateUsuarioDto) {
|
||||
@@ -27,69 +49,461 @@ export class UsuariosService {
|
||||
select: ['id_usuario'],
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!usuario) {
|
||||
throw new NotFoundException('Usuario no encontrado');
|
||||
}
|
||||
|
||||
const servActivo = await this.servActivosRepository.findOne({
|
||||
where: { usuario: { id_usuario: usuario.id_usuario } },
|
||||
|
||||
});
|
||||
|
||||
if (!servActivo) {
|
||||
throw new NotFoundException('Servicios no encontrados para el usuario');
|
||||
}
|
||||
|
||||
const resultado: {
|
||||
servicio: string;
|
||||
status: string;
|
||||
fecha_activacion: string | null;
|
||||
}[] = [];
|
||||
|
||||
const mapServicio = (nombre: string, estado: string | undefined) => {
|
||||
if (!estado) return;
|
||||
|
||||
// Transformar a formato plano
|
||||
let resultadoPlano = {};
|
||||
|
||||
if (servActivo.AT) {
|
||||
resultadoPlano = {
|
||||
AT: servActivo.ATStatus
|
||||
}
|
||||
}
|
||||
if (servActivo.Red) {
|
||||
resultadoPlano = {
|
||||
...resultadoPlano,
|
||||
Red: servActivo.RedStatus
|
||||
}
|
||||
}
|
||||
if (servActivo.Prestamos) {
|
||||
resultadoPlano = {
|
||||
...resultadoPlano,
|
||||
Prestamos: servActivo.PrestamosStatus
|
||||
}
|
||||
}
|
||||
if (servActivo.Correo) {
|
||||
resultadoPlano = {
|
||||
...resultadoPlano,
|
||||
Correo: servActivo.CorreoStatus
|
||||
if (estado.startsWith('Activo')) {
|
||||
const fechaCompleta = estado.substring(7); // "2025-06-25T14:26:21.427Z"
|
||||
const fechaSolo = fechaCompleta.substring(0, 10); // "2025-06-25"
|
||||
resultado.push({
|
||||
servicio: nombre,
|
||||
status: 'Activo',
|
||||
fecha_activacion: fechaSolo,
|
||||
});
|
||||
} else {
|
||||
resultado.push({
|
||||
servicio: nombre,
|
||||
status: 'Inactivo',
|
||||
fecha_activacion: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
mapServicio('Préstamo de equipo en CEDETEC', servActivo.ATStatus);
|
||||
mapServicio('Red', servActivo.RedStatus);
|
||||
mapServicio('Préstamo de equipo PC Puma', servActivo.PrestamosStatus);
|
||||
mapServicio('Correo', servActivo.CorreoStatus);
|
||||
|
||||
if (resultado.length === 0) {
|
||||
return [{
|
||||
servicio: 'Ninguno',
|
||||
status: 'No hay servicios activos para este usuario',
|
||||
fecha_activacion: null,
|
||||
}];
|
||||
}
|
||||
|
||||
// Si no hay servicios activos, retornar un objeto vacío
|
||||
if (Object.keys(resultadoPlano).length === 0) {
|
||||
resultadoPlano = {
|
||||
Servicios: 'No hay servicios activos para este usuario'
|
||||
};
|
||||
}
|
||||
console.log('Resultado plano:', resultadoPlano);
|
||||
|
||||
return [resultadoPlano]; // importante: frontend espera array
|
||||
|
||||
|
||||
|
||||
|
||||
return resultado;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
update(id: number, updateUsuarioDto: UpdateUsuarioDto) {
|
||||
return `This action updates a #${id} usuario`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Cron('0 6 27 * *') // minuto hora día mes díaDeSemana
|
||||
async tareaMensual() {
|
||||
this.logger.log('Ejecutando consulta mensual de profesores');
|
||||
await this.enviarSolicitud(); // tu función de importación
|
||||
}
|
||||
|
||||
async enviarSolicitud() {
|
||||
const mov = await this.movimientoService.log(
|
||||
'SISTEMA',
|
||||
'LOADING',
|
||||
'Enviando solicitud de consulta masiva de profesores al WebService',
|
||||
'CARGA MASIVA WEB SERVICE'
|
||||
);
|
||||
|
||||
interface DatosEntrada {
|
||||
Nombre: string;
|
||||
ApellidoPaterno: string;
|
||||
ApellidoMaterno: string;
|
||||
NumeroTrabajador: string;
|
||||
RFC: string;
|
||||
}
|
||||
|
||||
interface DatosRespuesta {
|
||||
numeroTrabajador: string;
|
||||
nombre: string;
|
||||
apellidoPaterno: string;
|
||||
apellidoMaterno: string;
|
||||
nombreCarrera: string;
|
||||
fechaNacimiento: string;
|
||||
rfc: string;
|
||||
genero: string;
|
||||
correoPersonal: string;
|
||||
nombramiento: string;
|
||||
unidadResponsable: string;
|
||||
curp: string;
|
||||
}
|
||||
|
||||
const apiUrl = process.env.API_URL;
|
||||
if (!apiUrl) {
|
||||
console.error("API_URL no está definida en las variables de entorno");
|
||||
return;
|
||||
}
|
||||
|
||||
const entrada: DatosEntrada = {
|
||||
Nombre: "",
|
||||
ApellidoPaterno: "",
|
||||
ApellidoMaterno: "",
|
||||
NumeroTrabajador: "",
|
||||
RFC: ""
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(apiUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(entrada)
|
||||
});
|
||||
|
||||
if (response.status === 400) {
|
||||
const errorText = await response.text();
|
||||
console.error("Error 400:", errorText);
|
||||
return;
|
||||
} else if (response.status === 204) {
|
||||
console.log("No se encontraron datos conforme a los criterios de búsqueda");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error("Error en la petición: " + response.statusText);
|
||||
|
||||
const json: DatosRespuesta[] = await response.json();
|
||||
|
||||
let nuevos = 0;
|
||||
let actualizados = 0;
|
||||
|
||||
let existe = await this.tipoUsuarioRepository.findOne({ where: { tipo_usuario: 'Profesor' } });
|
||||
if (!existe) {
|
||||
const tipoUsuario = this.tipoUsuarioRepository.create({ tipo_usuario: 'Profesor' });
|
||||
existe = await this.tipoUsuarioRepository.save(tipoUsuario);
|
||||
}
|
||||
|
||||
for (const prof of json) {
|
||||
try {
|
||||
if (!prof.rfc || !prof.nombre) {
|
||||
console.warn('Profesor con datos incompletos detectado:', prof);
|
||||
continue;
|
||||
}
|
||||
|
||||
const existente = await this.usuarioRepository.findOne({
|
||||
where: { rfc: prof.rfc },
|
||||
relations: ['genero']
|
||||
});
|
||||
|
||||
if (!existente) {
|
||||
let genero: Genero | null = null;
|
||||
if (prof.genero === 'M' || prof.genero === 'F') {
|
||||
const generoTexto = prof.genero === 'M' ? 'Masculino' : 'Femenino';
|
||||
genero = await this.generoRepository.findOne({ where: { genero: generoTexto } });
|
||||
if (!genero) {
|
||||
genero = await this.generoRepository.create({ genero: generoTexto });
|
||||
await this.generoRepository.save(genero);
|
||||
}
|
||||
}
|
||||
|
||||
let carrera = await this.carreraRepository.findOne({ where: { carrera: prof.nombreCarrera.trim() } })
|
||||
|
||||
if (!carrera) {
|
||||
const nuevaCarrera = await this.carreraRepository.create({ carrera: prof.nombreCarrera.trim(), clave: '' });
|
||||
carrera = await this.carreraRepository.save(nuevaCarrera);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const nuevo = await this.usuarioRepository.create({
|
||||
num_cuenta: prof.numeroTrabajador == '' ? undefined : prof.numeroTrabajador,
|
||||
nombre: prof.nombre,
|
||||
a_paterno: prof.apellidoPaterno,
|
||||
a_materno: prof.apellidoMaterno,
|
||||
rfc: prof.rfc,
|
||||
fecha_nacimiento: prof.fechaNacimiento,
|
||||
genero,
|
||||
|
||||
movimiento: mov
|
||||
});
|
||||
|
||||
const savedUser = await this.usuarioRepository.save(nuevo);
|
||||
|
||||
const servActivo = await this.servActivosRepository.create({
|
||||
ATStatus: 'Inactivo',
|
||||
RedStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
usuario: savedUser,
|
||||
AT: true,
|
||||
Red: prof.numeroTrabajador !== '',
|
||||
Prestamos: true,
|
||||
Correo: true
|
||||
});
|
||||
|
||||
await this.servActivosRepository.save(servActivo);
|
||||
|
||||
const userCarrera = await this.carreraUsuario.create({ carrera, usuario: savedUser });
|
||||
const usuarioTipo = await this.usuarioTipoUsuario.create({ tipoUsuario: existe, usuario: savedUser });
|
||||
|
||||
await this.carreraUsuario.save(userCarrera);
|
||||
await this.usuarioTipoUsuario.save(usuarioTipo);
|
||||
|
||||
nuevos++;
|
||||
} else {
|
||||
let cambios = false;
|
||||
|
||||
if (prof.numeroTrabajador && existente.num_cuenta !== prof.numeroTrabajador) {
|
||||
existente.num_cuenta = prof.numeroTrabajador;
|
||||
cambios = true;
|
||||
}
|
||||
if (existente.nombre !== prof.nombre) { existente.nombre = prof.nombre; cambios = true; }
|
||||
if (existente.a_paterno !== prof.apellidoPaterno) { existente.a_paterno = prof.apellidoPaterno; cambios = true; }
|
||||
if (existente.a_materno !== prof.apellidoMaterno) { existente.a_materno = prof.apellidoMaterno; cambios = true; }
|
||||
if (existente.rfc !== prof.rfc) { existente.rfc = prof.rfc; cambios = true; }
|
||||
if (existente.fecha_nacimiento !== prof.fechaNacimiento) { existente.fecha_nacimiento = prof.fechaNacimiento; cambios = true; }
|
||||
|
||||
if (cambios) {
|
||||
await this.usuarioRepository.save(existente);
|
||||
actualizados++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Progreso -> Nuevos: ${nuevos}, Actualizados: ${actualizados}`);
|
||||
} catch (innerError) {
|
||||
console.error('Error procesando profesor:', prof, innerError);
|
||||
}
|
||||
}
|
||||
this.movimientoService.updateStatus(mov.id_mov, 'SUCCESS', 'Carga masiva de web Service completa: ' + `Nuevos: ${nuevos}, Actualizados: ${actualizados}`)
|
||||
if (!process.env.EMAIL_USER) {
|
||||
throw new Error()
|
||||
}
|
||||
this.mailService.sendMail({
|
||||
to: process.env.EMAIL_USER,
|
||||
subject: 'Carga de datos exitosa',
|
||||
text: 'Carga masiva de web Service completa: ' + `Nuevos: ${nuevos}, Actualizados: ${actualizados}`,
|
||||
html: '<p></p>'
|
||||
})
|
||||
|
||||
this.excelService.enviarCargaMasiva();
|
||||
|
||||
return `Importación finalizada. Nuevos: ${nuevos}, Actualizados: ${actualizados}`;
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('Error al consultar profesores desde el WebService', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async cargaIndividual(usuario: CreateUsuarioDto, origen: string) {
|
||||
const queryRunner = this.usuarioRepository.manager.connection.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
try {
|
||||
const existente = await queryRunner.manager.findOne(Usuario, {
|
||||
where: { num_cuenta: usuario.num_cuenta },
|
||||
relations: ['genero'],
|
||||
});
|
||||
|
||||
if (existente) {
|
||||
throw new Error('Ya existe este usuario');
|
||||
}
|
||||
|
||||
const mov = await this.movimientoService.logger(queryRunner, origen, 'LOADING', undefined, 'CARGA INDIVIDUAL DE USUARIOS');
|
||||
|
||||
let genero: Genero | null = null;
|
||||
if (usuario.genero === 'M' || usuario.genero === 'F') {
|
||||
const generoTexto = usuario.genero === 'M' ? 'Masculino' : 'Femenino';
|
||||
genero = await queryRunner.manager.findOne(Genero, { where: { genero: generoTexto } });
|
||||
if (!genero) {
|
||||
genero = queryRunner.manager.create(Genero, { genero: generoTexto });
|
||||
await queryRunner.manager.save(genero);
|
||||
}
|
||||
}
|
||||
|
||||
let carrera = await queryRunner.manager.findOne(Carrera, { where: { carrera: usuario.carrera } });
|
||||
if (!carrera) {
|
||||
const nuevaCarrera = queryRunner.manager.create(Carrera, { carrera: usuario.carrera, clave: usuario.clave_carrera });
|
||||
carrera = await queryRunner.manager.save(nuevaCarrera);
|
||||
}
|
||||
|
||||
|
||||
const nuevo = queryRunner.manager.create(Usuario, {
|
||||
num_cuenta: usuario.num_cuenta,
|
||||
nombre: usuario.nombre,
|
||||
a_paterno: usuario.a_paterno,
|
||||
a_materno: usuario.a_materno,
|
||||
rfc: usuario.rfc ?? null,
|
||||
fecha_nacimiento: usuario.fecha_nacimiento,
|
||||
generacion: usuario.generacion ?? null,
|
||||
genero,
|
||||
movimiento: mov,
|
||||
});
|
||||
|
||||
const savedUser = await queryRunner.manager.save(nuevo);
|
||||
|
||||
const userCarrera = queryRunner.manager.create(CarreraUsuario, { carrera, usuario: savedUser });
|
||||
|
||||
const FieldMap = [
|
||||
'Diplomado', 'Extra Largo', 'Servicio Social', 'Idiomas R (UNAM)', 'Idiomas Sabatino',
|
||||
'Reinscrito', 'Posgrado', 'Intercambio UNAM', 'Movilidad', 'Ampliación de Conocimiento',
|
||||
'Licenciatura', 'Profesor', 'Trabajadores',
|
||||
];
|
||||
|
||||
if (!FieldMap.includes(usuario.tipo_usuario)) {
|
||||
throw new Error(`Tipo de usuario no permitido: ${usuario.tipo_usuario}`);
|
||||
}
|
||||
|
||||
// Verifica si el tipo de usuario ya existe
|
||||
let tipoUsuario = await queryRunner.manager.findOne(TipoUsuario, {
|
||||
where: { tipo_usuario: usuario.tipo_usuario },
|
||||
});
|
||||
|
||||
// Si no existe, lo crea y guarda
|
||||
if (!tipoUsuario) {
|
||||
tipoUsuario = queryRunner.manager.create(TipoUsuario, {
|
||||
tipo_usuario: usuario.tipo_usuario,
|
||||
});
|
||||
tipoUsuario = await queryRunner.manager.save(tipoUsuario);
|
||||
}
|
||||
|
||||
// Luego crea la relación con el usuario ya guardado
|
||||
const usuarioTipo = queryRunner.manager.create(UsuarioTipoUsuario, {
|
||||
tipoUsuario,
|
||||
usuario: savedUser,
|
||||
});
|
||||
await queryRunner.manager.save(usuarioTipo);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
switch (usuario.tipo_usuario.trim()) {
|
||||
|
||||
case 'Diplomado':
|
||||
|
||||
const servActivosDiplomado = this.servActivosRepository.create({
|
||||
Correo: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await queryRunner.manager.save(servActivosDiplomado);
|
||||
|
||||
break;
|
||||
|
||||
case 'Extra Largo':
|
||||
const servActivosExtraLargo = this.servActivosRepository.create({
|
||||
Prestamos: true,
|
||||
Correo: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
|
||||
});
|
||||
await queryRunner.manager.save(servActivosExtraLargo);
|
||||
break;
|
||||
|
||||
case 'Servicio Social':
|
||||
const servActivosServicio = this.servActivosRepository.create({
|
||||
Red: true,
|
||||
AT: true,
|
||||
Correo: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await queryRunner.manager.save(servActivosServicio);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 'Idiomas R (UNAM)':
|
||||
case 'Idiomas Sabatino':
|
||||
const servActivosIdiomas = this.servActivosRepository.create({
|
||||
Red: true,
|
||||
Correo: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await queryRunner.manager.save(servActivosIdiomas);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
case 'Reinscrito':
|
||||
case 'Posgrado':
|
||||
case 'Intercambio UNAM':
|
||||
case 'Movilidad':
|
||||
case 'Ampliación de Conocimiento':
|
||||
case 'Licenciatura':
|
||||
case 'Profesor':
|
||||
const servActivos = this.servActivosRepository.create({
|
||||
|
||||
Red: true,
|
||||
AT: true,
|
||||
Correo: true,
|
||||
Prestamos: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
ATStatus: 'Inactivo',
|
||||
CorreoStatus: 'Inactivo',
|
||||
PrestamosStatus: 'Inactivo',
|
||||
});
|
||||
await queryRunner.manager.save(servActivos);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 'Trabajadores':
|
||||
const servActivosTrabajadores = this.servActivosRepository.create({
|
||||
Red: true,
|
||||
usuario: savedUser,
|
||||
RedStatus: 'Inactivo',
|
||||
|
||||
});
|
||||
await queryRunner.manager.save(servActivosTrabajadores);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
console.log(savedUser)
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return { saved: savedUser, movId: mov.id_mov };
|
||||
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user