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:

+ `, + }); + + 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:

+ `, + }); + + 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(); + } + } } + +