diff --git a/.env(Example) b/.env(Example)
new file mode 100644
index 0000000..3db2053
--- /dev/null
+++ b/.env(Example)
@@ -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 =
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5818d64..68cf1dd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 77685cf..69e6dc3 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/app.module.ts b/src/app.module.ts
index 20b4306..a98f4f9 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -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],
diff --git a/src/entities/entities.ts b/src/entities/entities.ts
index 27d6c61..5a0ee55 100644
--- a/src/entities/entities.ts
+++ b/src/entities/entities.ts
@@ -88,7 +88,6 @@ export class Usuario {
@Column({
type: 'varchar',
- length: 9,
unique: true,
nullable: true,
default: null,
diff --git a/src/excel/dto/cargaIndividual.dto.ts b/src/excel/dto/cargaIndividual.dto.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/excel/excel.controller.ts b/src/excel/excel.controller.ts
index c1ad4ae..d8bc7af 100644
--- a/src/excel/excel.controller.ts
+++ b/src/excel/excel.controller.ts
@@ -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: `
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: '
No se pudieron subir datos.
',
+ });
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: ` Se han insertado ${result.inserted} registros.
+ Errores encontrados:
+ ${result.errors.map(error => `- ${error}
`).join('')}
`,
+ });
+
+ 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: `La carga de datos se ha realizado con éxito. Se han insertado ${result.inserted} registros.
+ Errores encontrados:
+ ${result.errors.map(error => `- ${error}
`).join('')}
`,
+ });
+
+ 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);
+
+ }
+
+
+
}
\ No newline at end of file
diff --git a/src/excel/excel.module.ts b/src/excel/excel.module.ts
index 984a73b..8fcef3b 100644
--- a/src/excel/excel.module.ts
+++ b/src/excel/excel.module.ts
@@ -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 { }
diff --git a/src/excel/excel.service.ts b/src/excel/excel.service.ts
index 189e1e5..1a36a1b 100644
--- a/src/excel/excel.service.ts
+++ b/src/excel/excel.service.ts
@@ -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,
@InjectRepository(ServActivos)
private readonly servActivosRepo: Repository,
+ @InjectRepository(UsuariosDelSistema)
+ private readonly usuariosDelSistemaRepo: Repository,
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 {
+ 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`);
+ }
+
+
+
+
+
}
diff --git a/src/mail/dto/send-email.dto.ts b/src/mail/dto/send-email.dto.ts
new file mode 100644
index 0000000..1ecf6fe
--- /dev/null
+++ b/src/mail/dto/send-email.dto.ts
@@ -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;
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/mail/mail.controller.ts b/src/mail/mail.controller.ts
new file mode 100644
index 0000000..bae8558
--- /dev/null
+++ b/src/mail/mail.controller.ts
@@ -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;
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/mail/mail.module.ts b/src/mail/mail.module.ts
new file mode 100644
index 0000000..2018716
--- /dev/null
+++ b/src/mail/mail.module.ts
@@ -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 { }
diff --git a/src/mail/mail.service.ts b/src/mail/mail.service.ts
new file mode 100644
index 0000000..8b0a898
--- /dev/null
+++ b/src/mail/mail.service.ts
@@ -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);
+ }
+
+
+
+}
diff --git a/src/movimiento/movimiento.module.ts b/src/movimiento/movimiento.module.ts
index 7275540..c93d9ad 100644
--- a/src/movimiento/movimiento.module.ts
+++ b/src/movimiento/movimiento.module.ts
@@ -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 { }
diff --git a/src/movimiento/movimiento.service.ts b/src/movimiento/movimiento.service.ts
index f91e5fd..7bdacea 100644
--- a/src/movimiento/movimiento.service.ts
+++ b/src/movimiento/movimiento.service.ts
@@ -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,
@InjectRepository(Origen)
private readonly origenRepo: Repository,
+ @InjectRepository(Usuario)
+ private readonly usuarioRepo: Repository,
) { }
/** Crea un registro de movimiento */
@@ -23,7 +25,14 @@ export class MovimientoService {
): Promise {
// 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 {
+ 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 {
@@ -56,8 +94,149 @@ export class MovimientoService {
await this.movRepo.save(movimiento);
}
- async findAll(): Promise {
- 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 {
+
+ 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;
}
diff --git a/src/usuarios/dto/create-usuario.dto.ts b/src/usuarios/dto/create-usuario.dto.ts
index d7960fe..27578fa 100644
--- a/src/usuarios/dto/create-usuario.dto.ts
+++ b/src/usuarios/dto/create-usuario.dto.ts
@@ -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;
+}
\ No newline at end of file
diff --git a/src/usuarios/usuarios.controller.ts b/src/usuarios/usuarios.controller.ts
index a0d1e65..21af1bf 100644
--- a/src/usuarios/usuarios.controller.ts
+++ b/src/usuarios/usuarios.controller.ts
@@ -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()
diff --git a/src/usuarios/usuarios.module.ts b/src/usuarios/usuarios.module.ts
index 1741048..ff4062c 100644
--- a/src/usuarios/usuarios.module.ts
+++ b/src/usuarios/usuarios.module.ts
@@ -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 { }
diff --git a/src/usuarios/usuarios.service.ts b/src/usuarios/usuarios.service.ts
index 251251c..65fe902 100644
--- a/src/usuarios/usuarios.service.ts
+++ b/src/usuarios/usuarios.service.ts
@@ -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,
- @InjectRepository(CarreraUsuario)
- private readonly carreraUsuarioRepository: Repository,
+ @InjectRepository(Carrera)
+ private readonly carreraRepository: Repository,
@InjectRepository(ServActivos)
private readonly servActivosRepository: Repository,
+ @InjectRepository(TipoUsuario)
+ private readonly tipoUsuarioRepository: Repository,
+ @InjectRepository(Genero)
+ private readonly generoRepository: Repository,
+ @InjectRepository(CarreraUsuario)
+ private readonly carreraUsuario: Repository,
+ @InjectRepository(UsuarioTipoUsuario)
+ private readonly usuarioTipoUsuario: Repository,
+ 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: ''
+ })
+
+ 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();
+ }
+ }
}
+
+