se cambio función
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
@@ -12,7 +11,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- ../.env
|
- ../.env
|
||||||
ports:
|
ports:
|
||||||
- "${DB_PORT}:3306"
|
- '${DB_PORT}:3306'
|
||||||
volumes:
|
volumes:
|
||||||
- mariadb_data:/var/lib/mysql
|
- mariadb_data:/var/lib/mysql
|
||||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
|||||||
@@ -37,11 +37,10 @@ export class ExcelController {
|
|||||||
private readonly movimientoService: MovimientoService,
|
private readonly movimientoService: MovimientoService,
|
||||||
private readonly mailService: MailService,
|
private readonly mailService: MailService,
|
||||||
private readonly usuarioService: UsuariosService, // Asegúrate de importar el servicio de correo
|
private readonly usuarioService: UsuariosService, // Asegúrate de importar el servicio de correo
|
||||||
) { }
|
) {}
|
||||||
|
|
||||||
@Post('carga')
|
@Post('carga')
|
||||||
async cargaUsuario(@Request() req, @Body() usuario: CreateUsuarioDto) {
|
async cargaUsuario(@Request() req, @Body() usuario: CreateUsuarioDto) {
|
||||||
|
|
||||||
if (req.user.origen != 'LOAD' && req.user.origen != 'EXTERNO') {
|
if (req.user.origen != 'LOAD' && req.user.origen != 'EXTERNO') {
|
||||||
throw new Error('Origen no permitido para carga');
|
throw new Error('Origen no permitido para carga');
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,11 @@ export class ExcelController {
|
|||||||
@Post('load')
|
@Post('load')
|
||||||
@UseInterceptors(FileInterceptor('file'))
|
@UseInterceptors(FileInterceptor('file'))
|
||||||
@ExcelDocumentation.loadExcel()
|
@ExcelDocumentation.loadExcel()
|
||||||
async loadExcel(@Request() req, @UploadedFile() file: Express.Multer.File, @Query('function') funcion?: number) {
|
async loadExcel(
|
||||||
|
@Request() req,
|
||||||
|
@UploadedFile() file: Express.Multer.File,
|
||||||
|
@Query('function') funcion?: number,
|
||||||
|
) {
|
||||||
const origen = req.user.origen; // ahora sí existe
|
const origen = req.user.origen; // ahora sí existe
|
||||||
|
|
||||||
if (origen != 'LOAD') {
|
if (origen != 'LOAD') {
|
||||||
@@ -123,19 +126,12 @@ export class ExcelController {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let result;
|
let result;
|
||||||
if(funcion==2){
|
if (funcion == 2) {
|
||||||
result = await this.excelService.loadFile2(
|
result = await this.excelService.loadFile2(file.buffer, req.user.email);
|
||||||
file.buffer,
|
} else {
|
||||||
req.user.email,
|
result = await this.excelService.loadFile(file.buffer, req.user.email);
|
||||||
);
|
|
||||||
}else{
|
|
||||||
result = await this.excelService.loadFile(
|
|
||||||
file.buffer,
|
|
||||||
req.user.email,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Actualizar el estado de los movimientos
|
//Actualizar el estado de los movimientos
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.mailService.sendMail({
|
this.mailService.sendMail({
|
||||||
@@ -248,12 +244,10 @@ export class ExcelController {
|
|||||||
'FAILED',
|
'FAILED',
|
||||||
'Origen no permitido para descarga',
|
'Origen no permitido para descarga',
|
||||||
);
|
);
|
||||||
return res
|
return res.status(HttpStatus.FORBIDDEN).json({
|
||||||
.status(HttpStatus.FORBIDDEN)
|
statusCode: 403,
|
||||||
.json({
|
message: 'Origen no permitido para descarga.',
|
||||||
statusCode: 403,
|
});
|
||||||
message: 'Origen no permitido para descarga.',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (origen == 'CORREO' || origen == 'LOAD') {
|
} else if (origen == 'CORREO' || origen == 'LOAD') {
|
||||||
try {
|
try {
|
||||||
@@ -334,17 +328,16 @@ export class ExcelController {
|
|||||||
'FAILED',
|
'FAILED',
|
||||||
'Origen no permitido para descarga',
|
'Origen no permitido para descarga',
|
||||||
);
|
);
|
||||||
return res
|
return res.status(HttpStatus.FORBIDDEN).json({
|
||||||
.status(HttpStatus.FORBIDDEN)
|
statusCode: 403,
|
||||||
.json({
|
message: 'Origen no permitido para descarga.',
|
||||||
statusCode: 403,
|
});
|
||||||
message: 'Origen no permitido para descarga.',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Agregarlo en su propio controller
|
//Agregarlo en su propio controller
|
||||||
@Get('movimientos')
|
@Get('movimientos')
|
||||||
|
@ExcelDocumentation.getMovimientos()
|
||||||
async getMovimientos(
|
async getMovimientos(
|
||||||
@Request() req,
|
@Request() req,
|
||||||
@Query('page') page: number,
|
@Query('page') page: number,
|
||||||
@@ -369,18 +362,15 @@ export class ExcelController {
|
|||||||
return { message: 'Servicios activados correctamente' };
|
return { message: 'Servicios activados correctamente' };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('cargaIndividual')
|
|
||||||
async cargarIndividual(@Request() req) {
|
|
||||||
const origen = req.user.origen; // ahora sí existe
|
|
||||||
return this.movimientoService.findAllCargaIndv(origen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('serv_act')
|
@Get('serv_act')
|
||||||
async serv(){
|
async serv() {
|
||||||
return await this.excelService.buscaAct()
|
return await this.excelService.buscaAct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('mov/:id_movimiento')
|
||||||
|
async MOV(@Param('id_movimiento', ParseIntPipe) id_movimiento: number) {
|
||||||
|
return await this.movimientoService.findAllWithRelations(id_movimiento);
|
||||||
|
}
|
||||||
// @Delete()
|
// @Delete()
|
||||||
// async borrar(){
|
// async borrar(){
|
||||||
// return await this.excelService.borrarUsers()
|
// return await this.excelService.borrarUsers()
|
||||||
|
|||||||
@@ -1,16 +1,55 @@
|
|||||||
import { applyDecorators } from '@nestjs/common';
|
import { applyDecorators } from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation, ApiConsumes, ApiBody, ApiResponse } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiTags,
|
||||||
|
ApiOperation,
|
||||||
|
ApiConsumes,
|
||||||
|
ApiBody,
|
||||||
|
ApiResponse,
|
||||||
|
ApiBearerAuth,
|
||||||
|
ApiQuery,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
|
|
||||||
export class ExcelDocumentation {
|
export class ExcelDocumentation {
|
||||||
/**
|
static getMovimientos() {
|
||||||
* Decorators Swagger para el endpoint POST /excel/verify
|
return applyDecorators(
|
||||||
*/
|
ApiBearerAuth(),
|
||||||
|
ApiOperation({
|
||||||
|
summary: 'Obtener movimientos',
|
||||||
|
description:
|
||||||
|
'Obtiene un listado paginado de movimientos según el origen del usuario autenticado.',
|
||||||
|
}),
|
||||||
|
ApiQuery({
|
||||||
|
name: 'page',
|
||||||
|
required: false,
|
||||||
|
type: Number,
|
||||||
|
example: 1,
|
||||||
|
description: 'Número de página',
|
||||||
|
}),
|
||||||
|
ApiQuery({
|
||||||
|
name: 'limit',
|
||||||
|
required: false,
|
||||||
|
type: Number,
|
||||||
|
example: 10,
|
||||||
|
description: 'Cantidad de registros por página',
|
||||||
|
}),
|
||||||
|
ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Listado de movimientos obtenido correctamente',
|
||||||
|
}),
|
||||||
|
ApiResponse({
|
||||||
|
status: 401,
|
||||||
|
description: 'No autorizado',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static verifyExcel() {
|
static verifyExcel() {
|
||||||
return applyDecorators(
|
return applyDecorators(
|
||||||
ApiTags('Excel'),
|
ApiTags('Excel'),
|
||||||
ApiOperation({
|
ApiOperation({
|
||||||
summary: 'Verificar archivo Excel',
|
summary: 'Verificar archivo Excel',
|
||||||
description: 'Valida duplicados, filas en blanco y formato básico de los datos sin realizar carga en la base.'
|
description:
|
||||||
|
'Valida duplicados, filas en blanco y formato básico de los datos sin realizar carga en la base.',
|
||||||
}),
|
}),
|
||||||
ApiConsumes('multipart/form-data'),
|
ApiConsumes('multipart/form-data'),
|
||||||
ApiBody({
|
ApiBody({
|
||||||
@@ -20,10 +59,10 @@ export class ExcelDocumentation {
|
|||||||
file: {
|
file: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
format: 'binary',
|
format: 'binary',
|
||||||
description: 'Archivo Excel (.xlsx) con usuarios a validar'
|
description: 'Archivo Excel (.xlsx) con usuarios a validar',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
ApiResponse({
|
ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -35,12 +74,18 @@ export class ExcelDocumentation {
|
|||||||
errors: {
|
errors: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: { type: 'string' },
|
items: { type: 'string' },
|
||||||
example: ['Fila 2: cuenta duplicada "42515101".', 'Fila 3: fecha de nacimiento inválida "1988051".']
|
example: [
|
||||||
}
|
'Fila 2: cuenta duplicada "42515101".',
|
||||||
}
|
'Fila 3: fecha de nacimiento inválida "1988051".',
|
||||||
}
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
ApiResponse({
|
||||||
|
status: 400,
|
||||||
|
description: 'No se recibió archivo o formato inválido.',
|
||||||
}),
|
}),
|
||||||
ApiResponse({ status: 400, description: 'No se recibió archivo o formato inválido.' })
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +97,8 @@ export class ExcelDocumentation {
|
|||||||
ApiTags('Excel'),
|
ApiTags('Excel'),
|
||||||
ApiOperation({
|
ApiOperation({
|
||||||
summary: 'Cargar archivo Excel',
|
summary: 'Cargar archivo Excel',
|
||||||
description: 'Valida y persiste los datos en la base de datos. Retorna el número de registros insertados.'
|
description:
|
||||||
|
'Valida y persiste los datos en la base de datos. Retorna el número de registros insertados.',
|
||||||
}),
|
}),
|
||||||
ApiConsumes('multipart/form-data'),
|
ApiConsumes('multipart/form-data'),
|
||||||
ApiBody({
|
ApiBody({
|
||||||
@@ -62,10 +108,10 @@ export class ExcelDocumentation {
|
|||||||
file: {
|
file: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
format: 'binary',
|
format: 'binary',
|
||||||
description: 'Archivo Excel (.xlsx) con usuarios a cargar'
|
description: 'Archivo Excel (.xlsx) con usuarios a cargar',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
ApiResponse({
|
ApiResponse({
|
||||||
status: 201,
|
status: 201,
|
||||||
@@ -73,9 +119,9 @@ export class ExcelDocumentation {
|
|||||||
schema: {
|
schema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
inserted: { type: 'number', example: 3 }
|
inserted: { type: 'number', example: 3 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
ApiResponse({
|
ApiResponse({
|
||||||
status: 400,
|
status: 400,
|
||||||
@@ -86,52 +132,37 @@ export class ExcelDocumentation {
|
|||||||
errors: {
|
errors: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: { type: 'string' },
|
items: { type: 'string' },
|
||||||
example: ['Fila 5: rfc contiene caracteres inválidos.']
|
example: ['Fila 5: rfc contiene caracteres inválidos.'],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static downloadExcel() {
|
static downloadExcel() {
|
||||||
return applyDecorators(
|
return applyDecorators(
|
||||||
ApiTags('Excel'),
|
ApiTags('Excel'),
|
||||||
//ApiBearerAuth('bearer'),
|
//ApiBearerAuth('bearer'),
|
||||||
ApiOperation({
|
ApiOperation({
|
||||||
summary: 'Descargar usuarios',
|
summary: 'Descargar usuarios',
|
||||||
description: 'Exporta todos los usuarios en un archivo TSV (o CSV) y registra el movimiento.'
|
description:
|
||||||
|
'Exporta todos los usuarios en un archivo TSV (o CSV) y registra el movimiento.',
|
||||||
}),
|
}),
|
||||||
ApiResponse({
|
ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'TSV generado correctamente',
|
description: 'TSV generado correctamente',
|
||||||
content: {
|
content: {
|
||||||
'text/tab-separated-values': {
|
'text/tab-separated-values': {
|
||||||
schema: { type: 'string', example: 'num_cuenta\\tnombre\\t...\\n...' }
|
schema: {
|
||||||
}
|
type: 'string',
|
||||||
}
|
example: 'num_cuenta\\tnombre\\t...\\n...',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
ApiResponse({ status: 401, description: 'No autorizado' }),
|
ApiResponse({ status: 401, description: 'No autorizado' }),
|
||||||
ApiResponse({ status: 500, description: 'Error al generar descarga' }),
|
ApiResponse({ status: 500, description: 'Error al generar descarga' }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+89
-137
@@ -34,7 +34,6 @@ export interface UsuarioRow {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExcelService {
|
export class ExcelService {
|
||||||
|
|
||||||
private readonly logger = new Logger(ExcelService.name);
|
private readonly logger = new Logger(ExcelService.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -59,7 +58,7 @@ export class ExcelService {
|
|||||||
private readonly dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
|
|
||||||
// … inyecta otros repositorios si los usarás
|
// … inyecta otros repositorios si los usarás
|
||||||
) { }
|
) {}
|
||||||
|
|
||||||
/** Lee el buffer del Excel y devuelve un arreglo de filas tipadas */
|
/** Lee el buffer del Excel y devuelve un arreglo de filas tipadas */
|
||||||
private async parseFile(buffer: Buffer): Promise<UsuarioRow[]> {
|
private async parseFile(buffer: Buffer): Promise<UsuarioRow[]> {
|
||||||
@@ -278,9 +277,8 @@ export class ExcelService {
|
|||||||
|
|
||||||
// 🔹 3. Arreglos para inserciones masivas
|
// 🔹 3. Arreglos para inserciones masivas
|
||||||
const usuarios: Usuario[] = [];
|
const usuarios: Usuario[] = [];
|
||||||
const carrerasUsuario: CarreraUsuario[] = [];
|
|
||||||
const usuariosTipos: UsuarioTipoUsuario[] = [];
|
const usuariosConRow: { usuario: Usuario; row: any }[] = [];
|
||||||
const serviciosActivos: ServActivos[] = [];
|
|
||||||
|
|
||||||
let contador = 0;
|
let contador = 0;
|
||||||
|
|
||||||
@@ -345,50 +343,84 @@ export class ExcelService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
usuarios.push(usuario);
|
usuarios.push(usuario);
|
||||||
|
usuariosConRow.push({ usuario, row: r });
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.manager.save([...mapGenero.values()]);
|
||||||
|
await queryRunner.manager.save([...mapCarreraClave.values()]);
|
||||||
|
await queryRunner.manager.save([...mapTipo.values()]);
|
||||||
|
|
||||||
|
await queryRunner.manager.save(usuarios);
|
||||||
|
|
||||||
|
const carrerasUsuarioFinal: CarreraUsuario[] = [];
|
||||||
|
|
||||||
|
for (const { usuario, row } of usuariosConRow) {
|
||||||
|
const carrera =
|
||||||
|
(row.clave && mapCarreraClave.get(row.clave)) ||
|
||||||
|
(row.nomCarr && mapCarreraNom.get(row.nomCarr));
|
||||||
|
|
||||||
if (carrera) {
|
if (carrera) {
|
||||||
const carreraUsuario = queryRunner.manager.create(CarreraUsuario, {
|
carrerasUsuarioFinal.push(
|
||||||
usuario,
|
queryRunner.manager.create(CarreraUsuario, {
|
||||||
carrera,
|
usuario,
|
||||||
});
|
carrera,
|
||||||
carrerasUsuario.push(carreraUsuario);
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
usuariosTipos.push(
|
await queryRunner.manager.save(carrerasUsuarioFinal);
|
||||||
|
|
||||||
|
const usuariosTiposFinal: UsuarioTipoUsuario[] = [];
|
||||||
|
|
||||||
|
for (const { usuario, row } of usuariosConRow) {
|
||||||
|
const tipo = mapTipo.get(row.tipo.trim());
|
||||||
|
if (!tipo) continue;
|
||||||
|
|
||||||
|
usuariosTiposFinal.push(
|
||||||
queryRunner.manager.create(UsuarioTipoUsuario, {
|
queryRunner.manager.create(UsuarioTipoUsuario, {
|
||||||
usuario,
|
usuario,
|
||||||
tipoUsuario: tipo,
|
tipoUsuario: tipo,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Servicios activos
|
await queryRunner.manager.save(usuariosTiposFinal);
|
||||||
const servData: Partial<ServActivos> = {
|
|
||||||
|
const serviciosActivosFinal: ServActivos[] = [];
|
||||||
|
|
||||||
|
for (const { usuario, row } of usuariosConRow) {
|
||||||
|
const serv = queryRunner.manager.create(ServActivos, {
|
||||||
usuario,
|
usuario,
|
||||||
|
Red: false,
|
||||||
|
AT: false,
|
||||||
|
Correo: false,
|
||||||
|
Prestamos: false,
|
||||||
RedStatus: 'Inactivo',
|
RedStatus: 'Inactivo',
|
||||||
ATStatus: 'Inactivo',
|
ATStatus: 'Inactivo',
|
||||||
CorreoStatus: 'Inactivo',
|
CorreoStatus: 'Inactivo',
|
||||||
PrestamosStatus: 'Inactivo',
|
PrestamosStatus: 'Inactivo',
|
||||||
};
|
});
|
||||||
|
|
||||||
switch (r.tipo.trim()) {
|
switch (row.tipo.trim()) {
|
||||||
case 'Diplomado':
|
case 'Diplomado':
|
||||||
Object.assign(servData, { Correo: true });
|
Object.assign(serv, { Correo: true });
|
||||||
conteoTiposCorreo++;
|
conteoTiposCorreo++;
|
||||||
break;
|
break;
|
||||||
case 'Extra Largo':
|
case 'Extra Largo':
|
||||||
Object.assign(servData, { Correo: true, Prestamos: true });
|
Object.assign(serv, { Correo: true, Prestamos: true });
|
||||||
conteoTiposCorreo++;
|
conteoTiposCorreo++;
|
||||||
conteoTiposSolicita++;
|
conteoTiposSolicita++;
|
||||||
break;
|
break;
|
||||||
case 'Servicio Social':
|
case 'Servicio Social':
|
||||||
Object.assign(servData, { Correo: true, AT: true, Red: true });
|
Object.assign(serv, { Correo: true, AT: true, Red: true });
|
||||||
conteoTiposCorreo++;
|
conteoTiposCorreo++;
|
||||||
conteoTiposAt++;
|
conteoTiposAt++;
|
||||||
conteoTiposRed++;
|
conteoTiposRed++;
|
||||||
break;
|
break;
|
||||||
case 'Idiomas R (UNAM)':
|
case 'Idiomas R (UNAM)':
|
||||||
case 'Idiomas Sabatino':
|
case 'Idiomas Sabatino':
|
||||||
Object.assign(servData, { Correo: true, Red: true });
|
Object.assign(serv, { Correo: true, Red: true });
|
||||||
conteoTiposCorreo++;
|
conteoTiposCorreo++;
|
||||||
conteoTiposRed++;
|
conteoTiposRed++;
|
||||||
break;
|
break;
|
||||||
@@ -399,7 +431,7 @@ export class ExcelService {
|
|||||||
case 'Ampliación de Conocimiento':
|
case 'Ampliación de Conocimiento':
|
||||||
case 'Licenciatura':
|
case 'Licenciatura':
|
||||||
case 'Profesor':
|
case 'Profesor':
|
||||||
Object.assign(servData, {
|
Object.assign(serv, {
|
||||||
Correo: true,
|
Correo: true,
|
||||||
AT: true,
|
AT: true,
|
||||||
Red: true,
|
Red: true,
|
||||||
@@ -411,79 +443,17 @@ export class ExcelService {
|
|||||||
conteoTiposSolicita++;
|
conteoTiposSolicita++;
|
||||||
break;
|
break;
|
||||||
case 'Trabajadores':
|
case 'Trabajadores':
|
||||||
Object.assign(servData, { Red: true });
|
Object.assign(serv, { Red: true });
|
||||||
conteoTiposRed++;
|
conteoTiposRed++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
serviciosActivos.push(
|
serviciosActivosFinal.push(serv);
|
||||||
queryRunner.manager.create(ServActivos, servData),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 4. Guardar en batch (orden correcto)
|
|
||||||
await queryRunner.manager.save([...mapGenero.values()]);
|
|
||||||
await queryRunner.manager.save([...mapCarreraClave.values()]);
|
|
||||||
await queryRunner.manager.save([...mapTipo.values()]);
|
|
||||||
|
|
||||||
// 1️⃣ Guardar usuarios primero — asigna IDs
|
|
||||||
await queryRunner.manager.save(usuarios);
|
|
||||||
|
|
||||||
// 2️⃣ Reconstruir relaciones con usuarios ya guardados
|
|
||||||
|
|
||||||
// CarreraUsuario
|
|
||||||
const carrerasUsuarioFinal: CarreraUsuario[] = [];
|
|
||||||
for (const cu of carrerasUsuario) {
|
|
||||||
const usuarioConId = usuarios.find(
|
|
||||||
(u) => u.num_cuenta === cu.usuario.num_cuenta,
|
|
||||||
);
|
|
||||||
if (usuarioConId && cu.carrera) {
|
|
||||||
carrerasUsuarioFinal.push(
|
|
||||||
queryRunner.manager.create(CarreraUsuario, {
|
|
||||||
usuario: usuarioConId,
|
|
||||||
carrera: cu.carrera,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UsuarioTipoUsuario
|
|
||||||
const usuariosTiposFinal: UsuarioTipoUsuario[] = [];
|
|
||||||
for (const ut of usuariosTipos) {
|
|
||||||
const usuarioConId = usuarios.find(
|
|
||||||
(u) => u.num_cuenta === ut.usuario.num_cuenta,
|
|
||||||
);
|
|
||||||
if (usuarioConId && ut.tipoUsuario) {
|
|
||||||
usuariosTiposFinal.push(
|
|
||||||
queryRunner.manager.create(UsuarioTipoUsuario, {
|
|
||||||
usuario: usuarioConId,
|
|
||||||
tipoUsuario: ut.tipoUsuario,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServActivos
|
|
||||||
const serviciosActivosFinal: ServActivos[] = [];
|
|
||||||
for (const sa of serviciosActivos) {
|
|
||||||
const usuarioConId = usuarios.find(
|
|
||||||
(u) => u.num_cuenta === sa.usuario.num_cuenta,
|
|
||||||
);
|
|
||||||
if (usuarioConId) {
|
|
||||||
serviciosActivosFinal.push(
|
|
||||||
queryRunner.manager.create(ServActivos, {
|
|
||||||
...sa,
|
|
||||||
usuario: usuarioConId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3️⃣ Guardar relaciones dependientes en orden
|
|
||||||
await queryRunner.manager.save(carrerasUsuarioFinal);
|
|
||||||
await queryRunner.manager.save(usuariosTiposFinal);
|
|
||||||
await queryRunner.manager.save(serviciosActivosFinal);
|
await queryRunner.manager.save(serviciosActivosFinal);
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
return {
|
return {
|
||||||
inserted: rows.length - contador,
|
inserted: rows.length - contador,
|
||||||
id_movimiento: movimiento.id_mov,
|
id_movimiento: movimiento.id_mov,
|
||||||
@@ -507,9 +477,6 @@ export class ExcelService {
|
|||||||
const errs = status.errors;
|
const errs = status.errors;
|
||||||
const rows = status.rowsGood;
|
const rows = status.rowsGood;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
'No se encontraron filas válidas para cargar. ' + errs,
|
'No se encontraron filas válidas para cargar. ' + errs,
|
||||||
@@ -524,7 +491,7 @@ export class ExcelService {
|
|||||||
const queryRunner = this.dataSource.createQueryRunner();
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
await queryRunner.connect();
|
await queryRunner.connect();
|
||||||
await queryRunner.startTransaction();
|
await queryRunner.startTransaction();
|
||||||
let idsUsuarios: number[] =[]
|
let idsUsuarios: number[] = [];
|
||||||
try {
|
try {
|
||||||
const movimiento = await this.movimientoService.logger(
|
const movimiento = await this.movimientoService.logger(
|
||||||
queryRunner,
|
queryRunner,
|
||||||
@@ -587,12 +554,13 @@ export class ExcelService {
|
|||||||
const serviciosActivos: ServActivos[] = [];
|
const serviciosActivos: ServActivos[] = [];
|
||||||
|
|
||||||
let contador = 0;
|
let contador = 0;
|
||||||
|
|
||||||
for (const r of rows) {
|
for (const r of rows) {
|
||||||
if (setCuentas.has(r.cuenta) || (r.rfc && setRfcs.has(r.rfc))) {
|
if (setCuentas.has(r.cuenta) || (r.rfc && setRfcs.has(r.rfc))) {
|
||||||
const use= existentes.find( u => u.num_cuenta === r.cuenta || u.rfc === r.rfc)
|
const use = existentes.find(
|
||||||
if(use?.id_usuario)
|
(u) => u.num_cuenta === r.cuenta || u.rfc === r.rfc,
|
||||||
idsUsuarios.push(use?.id_usuario)
|
);
|
||||||
|
if (use?.id_usuario) idsUsuarios.push(use?.id_usuario);
|
||||||
contador++;
|
contador++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -651,7 +619,7 @@ export class ExcelService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
usuarios.push(usuario);
|
usuarios.push(usuario);
|
||||||
|
|
||||||
if (carrera) {
|
if (carrera) {
|
||||||
const carreraUsuario = queryRunner.manager.create(CarreraUsuario, {
|
const carreraUsuario = queryRunner.manager.create(CarreraUsuario, {
|
||||||
usuario,
|
usuario,
|
||||||
@@ -734,10 +702,8 @@ export class ExcelService {
|
|||||||
|
|
||||||
// 1️⃣ Guardar usuarios primero — asigna IDs
|
// 1️⃣ Guardar usuarios primero — asigna IDs
|
||||||
await queryRunner.manager.save(usuarios);
|
await queryRunner.manager.save(usuarios);
|
||||||
idsUsuarios = usuarios.map(u => u.id_usuario);
|
idsUsuarios = usuarios.map((u) => u.id_usuario);
|
||||||
idsUsuarios.push(
|
idsUsuarios.push(...existentes.map((e) => e.id_usuario));
|
||||||
...existentes.map(e => e.id_usuario)
|
|
||||||
);
|
|
||||||
// 2️⃣ Reconstruir relaciones con usuarios ya guardados
|
// 2️⃣ Reconstruir relaciones con usuarios ya guardados
|
||||||
|
|
||||||
// CarreraUsuario
|
// CarreraUsuario
|
||||||
@@ -793,11 +759,6 @@ export class ExcelService {
|
|||||||
await queryRunner.manager.save(usuariosTiposFinal);
|
await queryRunner.manager.save(usuariosTiposFinal);
|
||||||
await queryRunner.manager.save(serviciosActivosFinal);
|
await queryRunner.manager.save(serviciosActivosFinal);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
inserted: rows.length - contador,
|
inserted: rows.length - contador,
|
||||||
id_movimiento: movimiento.id_mov,
|
id_movimiento: movimiento.id_mov,
|
||||||
@@ -812,26 +773,22 @@ export class ExcelService {
|
|||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
await queryRunner.release();
|
await queryRunner.release();
|
||||||
|
|
||||||
await this.servActivosRepo
|
await this.servActivosRepo
|
||||||
.createQueryBuilder()
|
.createQueryBuilder()
|
||||||
.update()
|
.update()
|
||||||
.set({
|
.set({
|
||||||
Red: false,
|
Red: false,
|
||||||
Prestamos: false,
|
Prestamos: false,
|
||||||
AT: false,
|
AT: false,
|
||||||
Correo: false,
|
Correo: false,
|
||||||
RedStatus: 'Inactivo',
|
RedStatus: 'Inactivo',
|
||||||
PrestamosStatus: 'Inactivo',
|
PrestamosStatus: 'Inactivo',
|
||||||
ATStatus: 'Inactivo',
|
ATStatus: 'Inactivo',
|
||||||
CorreoStatus: 'Inactivo',
|
CorreoStatus: 'Inactivo',
|
||||||
})
|
})
|
||||||
.where('id_usuario NOT IN (:...ids)', { ids: idsUsuarios })
|
.where('id_usuario NOT IN (:...ids)', { ids: idsUsuarios })
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,7 +1167,6 @@ export class ExcelService {
|
|||||||
'Carga de Usuarios',
|
'Carga de Usuarios',
|
||||||
`Se ha realizado una carga de usuarios en el sistema. Nuevos: ${data?.nuevos ?? 0}, Actualizados: ${data?.actualizados ?? 0}`,
|
`Se ha realizado una carga de usuarios en el sistema. Nuevos: ${data?.nuevos ?? 0}, Actualizados: ${data?.actualizados ?? 0}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async enviarInforme(
|
async enviarInforme(
|
||||||
@@ -1238,18 +1194,14 @@ export class ExcelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async buscaAct() {
|
async buscaAct() {
|
||||||
return await this.servActivosRepo.find({
|
return await this.servActivosRepo.find({
|
||||||
where: [
|
where: [
|
||||||
{ AT: true },
|
{ AT: true },
|
||||||
{ Correo: true },
|
{ Correo: true },
|
||||||
{ Prestamos: true },
|
{ Prestamos: true },
|
||||||
{ Red: true },
|
{ Red: true },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export class MovimientoService {
|
|||||||
private readonly origenRepo: Repository<Origen>,
|
private readonly origenRepo: Repository<Origen>,
|
||||||
@InjectRepository(Usuario)
|
@InjectRepository(Usuario)
|
||||||
private readonly usuarioRepo: Repository<Usuario>,
|
private readonly usuarioRepo: Repository<Usuario>,
|
||||||
) { }
|
) {}
|
||||||
|
|
||||||
/** Crea un registro de movimiento */
|
/** Crea un registro de movimiento */
|
||||||
async log(
|
async log(
|
||||||
@@ -54,7 +54,7 @@ export class MovimientoService {
|
|||||||
origenNombre: string,
|
origenNombre: string,
|
||||||
status: string,
|
status: string,
|
||||||
observaciones?: string,
|
observaciones?: string,
|
||||||
reporte?: string
|
reporte?: string,
|
||||||
): Promise<Movimiento> {
|
): Promise<Movimiento> {
|
||||||
const origenEntidad = await queryRunner.manager.findOne(Origen, {
|
const origenEntidad = await queryRunner.manager.findOne(Origen, {
|
||||||
where: { origen: origenNombre },
|
where: { origen: origenNombre },
|
||||||
@@ -76,17 +76,21 @@ export class MovimientoService {
|
|||||||
return await queryRunner.manager.save(nuevoMov);
|
return await queryRunner.manager.save(nuevoMov);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Actualiza el status de un movimiento existente */
|
/** Actualiza el status de un movimiento existente */
|
||||||
async updateStatus(id_movimiento: number, nuevoStatus: string, observaciones?: string): Promise<void> {
|
async updateStatus(
|
||||||
const movimiento = await this.movRepo.findOne({ where: { id_mov: id_movimiento } });
|
id_movimiento: number,
|
||||||
|
nuevoStatus: string,
|
||||||
|
observaciones?: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const movimiento = await this.movRepo.findOne({
|
||||||
|
where: { id_mov: id_movimiento },
|
||||||
|
});
|
||||||
|
|
||||||
if (!movimiento) {
|
if (!movimiento) {
|
||||||
throw new Error(`Movimiento con ID ${id_movimiento} no encontrado`);
|
throw new Error(`Movimiento con ID ${id_movimiento} no encontrado`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('movimiento' + movimiento);
|
||||||
movimiento.status = nuevoStatus;
|
movimiento.status = nuevoStatus;
|
||||||
movimiento.observaciones = observaciones || movimiento.observaciones; // opcional: actualizar observaciones
|
movimiento.observaciones = observaciones || movimiento.observaciones; // opcional: actualizar observaciones
|
||||||
movimiento.fecha_mov = new Date(); // opcional: actualizar fecha
|
movimiento.fecha_mov = new Date(); // opcional: actualizar fecha
|
||||||
@@ -98,8 +102,12 @@ export class MovimientoService {
|
|||||||
origen: string,
|
origen: string,
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
limit: number = 10,
|
limit: number = 10,
|
||||||
): Promise<{ move: any[]; button: boolean; total?: number; lastPage?: number }> {
|
): Promise<{
|
||||||
|
move: any[];
|
||||||
|
button: boolean;
|
||||||
|
total?: number;
|
||||||
|
lastPage?: number;
|
||||||
|
}> {
|
||||||
if (origen === 'LOAD') {
|
if (origen === 'LOAD') {
|
||||||
const [movimientos, total] = await this.movRepo.findAndCount({
|
const [movimientos, total] = await this.movRepo.findAndCount({
|
||||||
where: {
|
where: {
|
||||||
@@ -136,8 +144,6 @@ export class MovimientoService {
|
|||||||
SOLICITA: 'Prestamos',
|
SOLICITA: 'Prestamos',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
||||||
const origenField = FieldMap[origen as keyof typeof FieldMap];
|
const origenField = FieldMap[origen as keyof typeof FieldMap];
|
||||||
|
|
||||||
@@ -147,7 +153,6 @@ export class MovimientoService {
|
|||||||
origen: { origen: 'LOAD' },
|
origen: { origen: 'LOAD' },
|
||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
reporte: 'CARGA MASIVA DE USUARIOS',
|
reporte: 'CARGA MASIVA DE USUARIOS',
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -156,23 +161,16 @@ export class MovimientoService {
|
|||||||
origen: { origen: 'SISTEMA' },
|
origen: { origen: 'SISTEMA' },
|
||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
reporte: 'CARGA MASIVA WEB SERVICE',
|
reporte: 'CARGA MASIVA WEB SERVICE',
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const mov2 = await this.movRepo.find({
|
const mov2 = await this.movRepo.find({
|
||||||
where: {
|
where: {
|
||||||
|
|
||||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const todosLosMovimientos = [...movimientos, ...mov, ...mov2];
|
const todosLosMovimientos = [...movimientos, ...mov, ...mov2];
|
||||||
return { move: todosLosMovimientos, button: false };
|
return { move: todosLosMovimientos, button: false };
|
||||||
}
|
}
|
||||||
@@ -186,7 +184,7 @@ export class MovimientoService {
|
|||||||
servActivo: {
|
servActivo: {
|
||||||
[origenField]: true,
|
[origenField]: true,
|
||||||
|
|
||||||
[field]: 'Inactivo'
|
[field]: 'Inactivo',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -199,20 +197,19 @@ export class MovimientoService {
|
|||||||
usuario: {
|
usuario: {
|
||||||
servActivo: {
|
servActivo: {
|
||||||
[origenField]: true,
|
[origenField]: true,
|
||||||
[field]: 'Inactivo'
|
[field]: 'Inactivo',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const mov2 = await this.movRepo.find({
|
const mov2 = await this.movRepo.find({
|
||||||
where: {
|
where: {
|
||||||
|
|
||||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||||
status: 'SUCCESS',
|
status: 'SUCCESS',
|
||||||
usuario: {
|
usuario: {
|
||||||
servActivo: {
|
servActivo: {
|
||||||
[origenField]: true,
|
[origenField]: true,
|
||||||
[field]: 'Inactivo'
|
[field]: 'Inactivo',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -224,7 +221,6 @@ export class MovimientoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findAllCargaIndv(origen): Promise<Usuario[]> {
|
async findAllCargaIndv(origen): Promise<Usuario[]> {
|
||||||
|
|
||||||
const statusFieldMap = {
|
const statusFieldMap = {
|
||||||
AT: 'ATStatus',
|
AT: 'ATStatus',
|
||||||
RED: 'RedStatus',
|
RED: 'RedStatus',
|
||||||
@@ -239,10 +235,6 @@ export class MovimientoService {
|
|||||||
SOLICITA: 'Prestamos',
|
SOLICITA: 'Prestamos',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
const field = statusFieldMap[origen as keyof typeof statusFieldMap];
|
||||||
|
|
||||||
const origenField = FieldMap[origen as keyof typeof FieldMap];
|
const origenField = FieldMap[origen as keyof typeof FieldMap];
|
||||||
@@ -254,7 +246,6 @@ export class MovimientoService {
|
|||||||
const usuarios = await this.usuarioRepo.find({
|
const usuarios = await this.usuarioRepo.find({
|
||||||
where: {
|
where: {
|
||||||
movimiento: {
|
movimiento: {
|
||||||
|
|
||||||
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
reporte: 'CARGA INDIVIDUAL DE USUARIOS',
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -262,18 +253,27 @@ export class MovimientoService {
|
|||||||
[field]: 'Inactivo',
|
[field]: 'Inactivo',
|
||||||
[origenField]: true,
|
[origenField]: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return usuarios;
|
return usuarios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findAllWithRelations(id: number): Promise<Movimiento[]> {
|
||||||
|
return await this.movRepo.find({
|
||||||
|
where: { id_mov: id },
|
||||||
|
relations: [
|
||||||
|
'usuario',
|
||||||
|
'origen',
|
||||||
|
'usuario.servActivo',
|
||||||
|
'usuario.carreraUsuarios',
|
||||||
|
'usuario.carreraUsuarios.carrera',
|
||||||
|
'usuario.usuarioTipos',
|
||||||
|
'usuario.usuarioTipos.tipoUsuario',
|
||||||
|
],
|
||||||
|
order: {
|
||||||
|
fecha_mov: 'DESC',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user