From 8d191fbb23ebffb5c07f8c50ab1c8b39554bb157 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 2 Apr 2025 15:56:34 -0600 Subject: [PATCH] registrar el evento cuando se crea en el formulario --- src/cuestionario/cuestionario.module.ts | 7 +- src/cuestionario/cuestionario.service.ts | 81 ++++++++++++++++++- .../dto/create-cuestionario.dto.ts | 38 +++++++++ .../dto/update-cuestionario.dto.ts | 13 ++- .../entities/cuestionario.entity.ts | 10 ++- .../cuestionario_respondido.service.ts | 55 +++++++++++-- src/qr/qr.service.ts | 1 + utils/crear_formulario_feria.ts | 1 + 8 files changed, 191 insertions(+), 15 deletions(-) diff --git a/src/cuestionario/cuestionario.module.ts b/src/cuestionario/cuestionario.module.ts index 400dd2a..b759268 100644 --- a/src/cuestionario/cuestionario.module.ts +++ b/src/cuestionario/cuestionario.module.ts @@ -11,6 +11,8 @@ import { Opcion } from '../opcion/entities/opcion.entity'; import { PreguntaOpcion } from '../pregunta_opcion/entities/pregunta_opcion.entity'; import { TipoPregunta } from '../tipo_pregunta/entities/tipo_pregunta.entity'; import { TipoCuestionario } from '../tipo_cuestionario/entities/tipo_cuestionario.entity'; +import { Evento } from '../evento/evento.entity'; +import { EventoService } from '../evento/evento.service'; @Module({ imports: [ @@ -23,11 +25,12 @@ import { TipoCuestionario } from '../tipo_cuestionario/entities/tipo_cuestionari Opcion, PreguntaOpcion, TipoPregunta, - TipoCuestionario + TipoCuestionario, + Evento ]) ], controllers: [CuestionarioController], - providers: [CuestionarioService], + providers: [CuestionarioService, EventoService], exports: [TypeOrmModule, CuestionarioService] }) export class CuestionarioModule {} diff --git a/src/cuestionario/cuestionario.service.ts b/src/cuestionario/cuestionario.service.ts index 0f4454f..c31361a 100644 --- a/src/cuestionario/cuestionario.service.ts +++ b/src/cuestionario/cuestionario.service.ts @@ -12,6 +12,8 @@ import { Opcion } from '../opcion/entities/opcion.entity'; import { PreguntaOpcion } from '../pregunta_opcion/entities/pregunta_opcion.entity'; import { TipoPregunta } from '../tipo_pregunta/entities/tipo_pregunta.entity'; import { TipoCuestionario } from '../tipo_cuestionario/entities/tipo_cuestionario.entity'; +import { Evento } from '../evento/evento.entity'; +import { EventoService } from '../evento/evento.service'; @Injectable() export class CuestionarioService { @@ -32,7 +34,10 @@ export class CuestionarioService { private preguntaOpcionRepository: Repository, @InjectRepository(TipoPregunta) private tipoPreguntaRepository: Repository, + @InjectRepository(Evento) + private eventoRepository: Repository, private dataSource: DataSource, + private eventoService: EventoService ) {} async create(createCuestionarioDto: CreateCuestionarioDto) { @@ -41,6 +46,33 @@ export class CuestionarioService { await queryRunner.startTransaction(); try { + // Verificar si se especificó un evento y búscarlo/crearlo + let idEvento: number | undefined = undefined; + + if (createCuestionarioDto.evento) { + // Buscar si el evento ya existe + let evento = await this.eventoRepository.findOne({ + where: { nombre_evento: createCuestionarioDto.evento } + }); + + // Si no existe, crearlo + if (!evento) { + const nuevoEvento = { + nombre_evento: createCuestionarioDto.evento, + tipo_evento: 'Predeterminado', + fecha_inicio: createCuestionarioDto.fecha_inicio || new Date(), + fecha_fin: createCuestionarioDto.fecha_fin || new Date(Date.now() + 86400000) // 1 día después si no hay fecha + }; + + evento = await queryRunner.manager.save(Evento, nuevoEvento); + console.log(`Evento creado: ${evento.nombre_evento}, ID: ${evento.id_evento}`); + } else { + console.log(`Evento encontrado: ${evento.nombre_evento}, ID: ${evento.id_evento}`); + } + + idEvento = evento.id_evento; + } + // 1. Crear cuestionario const cuestionario = new Cuestionario(); cuestionario.nombre_form = createCuestionarioDto.nombre_form; @@ -50,6 +82,11 @@ export class CuestionarioService { cuestionario.id_tipo_cuestionario = createCuestionarioDto.id_tipo_cuestionario; cuestionario.contador_secciones = createCuestionarioDto.secciones?.length || 0; cuestionario.editable = true; + + // Asociar el cuestionario con el evento si existe + if (idEvento !== undefined) { + cuestionario.id_evento = idEvento; + } const savedCuestionario = await queryRunner.manager.save(cuestionario); @@ -172,7 +209,8 @@ export class CuestionarioService { async findCompleto(id: number) { // Obtener el cuestionario básico const cuestionario = await this.cuestionarioRepository.findOne({ - where: { id_cuestionario: id } + where: { id_cuestionario: id }, + relations: ['evento'] // Incluir la relación con el evento }); if (!cuestionario) { @@ -294,6 +332,13 @@ export class CuestionarioService { id_tipo_cuestionario: tipoCuestionario.id_tipo_cuestionario, tipo_cuestionario: tipoCuestionario.tipo_cuestionario }, + evento: cuestionario.evento ? { + id_evento: cuestionario.evento.id_evento, + nombre_evento: cuestionario.evento.nombre_evento, + tipo_evento: cuestionario.evento.tipo_evento, + fecha_inicio: cuestionario.evento.fecha_inicio ? cuestionario.evento.fecha_inicio.toISOString() : null, + fecha_fin: cuestionario.evento.fecha_fin ? cuestionario.evento.fecha_fin.toISOString() : null + } : null, cuestionario: { id_cuestionario: cuestionario.id_cuestionario, nombre_form: cuestionario.nombre_form, @@ -304,13 +349,43 @@ export class CuestionarioService { fecha_fin: cuestionario.fecha_fin ? cuestionario.fecha_fin.toISOString() : null, id_cuestionario_original: cuestionario.id_cuestionario_original, id_tipo_cuestionario: cuestionario.id_tipo_cuestionario, + id_evento: cuestionario.id_evento || null, secciones: seccionesFormateadas } }; } - update(id: number, updateCuestionarioDto: UpdateCuestionarioDto) { - return this.cuestionarioRepository.update(id, updateCuestionarioDto); + async update(id: number, updateCuestionarioDto: UpdateCuestionarioDto) { + // Si el DTO incluye el campo "evento" (string), debemos procesarlo aparte + if (updateCuestionarioDto.evento) { + // Buscar o crear evento + let evento = await this.eventoRepository.findOne({ + where: { nombre_evento: updateCuestionarioDto.evento } + }); + + if (!evento) { + // Crear el evento + const nuevoEvento = { + nombre_evento: updateCuestionarioDto.evento, + tipo_evento: 'Predeterminado', + fecha_inicio: new Date(), + fecha_fin: new Date(Date.now() + 86400000) + }; + + evento = await this.eventoRepository.save(nuevoEvento); + } + + // Asignar el ID del evento al DTO de actualización + updateCuestionarioDto.id_evento = evento.id_evento; + + // Eliminar la propiedad evento para evitar conflictos + delete updateCuestionarioDto.evento; + } + + // Preparar los datos para la actualización + const updateData: any = { ...updateCuestionarioDto }; + + return this.cuestionarioRepository.update(id, updateData); } remove(id: number) { diff --git a/src/cuestionario/dto/create-cuestionario.dto.ts b/src/cuestionario/dto/create-cuestionario.dto.ts index 2930547..ee07e94 100644 --- a/src/cuestionario/dto/create-cuestionario.dto.ts +++ b/src/cuestionario/dto/create-cuestionario.dto.ts @@ -1,28 +1,66 @@ import { CreateSeccionDto } from '../../seccion/dto/create-seccion.dto'; import { IsArray, IsDateString, IsNotEmpty, IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; +import { ApiProperty } from '@nestjs/swagger'; export class CreateCuestionarioDto { + @ApiProperty({ + description: 'Nombre del formulario', + example: 'Registro para la Feria de la Sexualidad - FES Acatlán' + }) @IsNotEmpty() @IsString() nombre_form: string; + @ApiProperty({ + description: 'Descripción del formulario', + example: 'Formulario de registro para la feria...', + required: false + }) @IsOptional() @IsString() descripcion?: string; + @ApiProperty({ + description: 'Fecha de inicio', + example: '2025-03-26T00:00:00', + required: false + }) @IsOptional() @IsDateString() fecha_inicio?: Date; + @ApiProperty({ + description: 'Fecha de fin', + example: '2025-03-31T23:59:59', + required: false + }) @IsOptional() @IsDateString() fecha_fin?: Date; + @ApiProperty({ + description: 'ID del tipo de cuestionario', + example: 1 + }) @IsNotEmpty() @IsNumber() id_tipo_cuestionario: number; + + @ApiProperty({ + description: 'Nombre del evento asociado', + example: 'Feria de la Sexualidad', + required: false + }) + @IsOptional() + @IsString() + evento?: string; + @ApiProperty({ + description: 'Secciones del cuestionario', + type: [CreateSeccionDto], + required: false + }) @IsOptional() @IsArray() @ValidateNested({ each: true }) diff --git a/src/cuestionario/dto/update-cuestionario.dto.ts b/src/cuestionario/dto/update-cuestionario.dto.ts index f275e73..3f72844 100644 --- a/src/cuestionario/dto/update-cuestionario.dto.ts +++ b/src/cuestionario/dto/update-cuestionario.dto.ts @@ -1,4 +1,15 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateCuestionarioDto } from './create-cuestionario.dto'; +import { IsNumber, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; -export class UpdateCuestionarioDto extends PartialType(CreateCuestionarioDto) {} +export class UpdateCuestionarioDto extends PartialType(CreateCuestionarioDto) { + @ApiProperty({ + description: 'ID del evento asociado', + example: 1, + required: false + }) + @IsOptional() + @IsNumber() + id_evento?: number; +} diff --git a/src/cuestionario/entities/cuestionario.entity.ts b/src/cuestionario/entities/cuestionario.entity.ts index d7559d8..535d2b2 100644 --- a/src/cuestionario/entities/cuestionario.entity.ts +++ b/src/cuestionario/entities/cuestionario.entity.ts @@ -1,6 +1,7 @@ import { CuestionarioSeccion } from 'src/cuestionario_seccion/entities/cuestionario_seccion.entity'; +import { Evento } from 'src/evento/evento.entity'; import { TipoCuestionario } from 'src/tipo_cuestionario/entities/tipo_cuestionario.entity'; -import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToMany, ManyToOne } from 'typeorm'; +import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToMany, ManyToOne, JoinColumn } from 'typeorm'; @@ -39,4 +40,11 @@ export class Cuestionario { @ManyToOne(()=> Cuestionario) cuestionarioOriginal: Cuestionario; + + @Column({ type: 'int', nullable: true }) + id_evento: number; + + @ManyToOne(() => Evento) + @JoinColumn({ name: 'id_evento' }) + evento: Evento; } diff --git a/src/cuestionario_respondido/cuestionario_respondido.service.ts b/src/cuestionario_respondido/cuestionario_respondido.service.ts index c273278..d007d54 100644 --- a/src/cuestionario_respondido/cuestionario_respondido.service.ts +++ b/src/cuestionario_respondido/cuestionario_respondido.service.ts @@ -157,17 +157,15 @@ export class CuestionarioRespondidoService { } async findOne(id: number) { + // Obtener cuestionario respondido con sus relaciones básicas const cuestionarioRespondido = await this.cuestionarioRespondidoRepository.findOne({ where: { idCuestionarioRespondido: id }, relations: [ - 'participante', - 'cuestionario', - 'respuestasAbiertas', + 'participante', + 'cuestionario', + 'respuestasAbiertas', 'respuestasAbiertas.pregunta', - 'respuestasCerradas', - 'respuestasCerradas.preguntaOpcion', - 'respuestasCerradas.preguntaOpcion.opcion', - 'respuestasCerradas.preguntaOpcion.pregunta' + 'respuestasCerradas' ] }); @@ -175,7 +173,48 @@ export class CuestionarioRespondidoService { throw new NotFoundException(`Cuestionario respondido con ID ${id} no encontrado`); } - return cuestionarioRespondido; + // Obtener directamente los datos de respuestas cerradas desde la base de datos + // usando una consulta SQL directa + const respuestasCerradas = await this.dataSource.query(` + SELECT + rpc.idRespuestaParticipanteCerrada, + rpc.id_pregunta_opcion, + po.id_pregunta, + p.texto_pregunta, + p.id_tipo_pregunta, + o.id_opcion, + o.opcion + FROM respuesta_participante_cerrada rpc + LEFT JOIN pregunta_opcion po ON rpc.id_pregunta_opcion = po.id_pregunta_opcion + LEFT JOIN pregunta p ON po.id_pregunta = p.id_pregunta + LEFT JOIN opcion o ON po.id_opcion = o.id_opcion + WHERE rpc.id_cuestionario_respondido = ? + `, [id]); + + console.log('Respuestas cerradas SQL:', JSON.stringify(respuestasCerradas, null, 2)); + + // Transformar las respuestas cerradas al formato deseado + const respuestasCerradasFormateadas = respuestasCerradas.map(respuesta => ({ + idRespuestaParticipanteCerrada: respuesta.idRespuestaParticipanteCerrada, + id_pregunta_opcion: respuesta.id_pregunta_opcion, + pregunta: { + id_pregunta: respuesta.id_pregunta, + texto_pregunta: respuesta.texto_pregunta, + id_tipo_pregunta: respuesta.id_tipo_pregunta + }, + opcion: { + id_opcion: respuesta.id_opcion, + opcion: respuesta.opcion + } + })); + + // Crear el objeto de respuesta con el formato deseado + const resultado = { + ...cuestionarioRespondido, + respuestasCerradas: respuestasCerradasFormateadas + }; + + return resultado; } update(id: number, updateCuestionarioRespondidoDto: UpdateCuestionarioRespondidoDto) { diff --git a/src/qr/qr.service.ts b/src/qr/qr.service.ts index 5a46450..2d24321 100644 --- a/src/qr/qr.service.ts +++ b/src/qr/qr.service.ts @@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { CreateQrDto } from './dto/create-qr.dto'; import { UpdateQrDto } from './dto/update.qr.dto'; +// @ts-ignore import * as QRCode from 'qrcode'; @Injectable() diff --git a/utils/crear_formulario_feria.ts b/utils/crear_formulario_feria.ts index 644269f..5f9e9d8 100644 --- a/utils/crear_formulario_feria.ts +++ b/utils/crear_formulario_feria.ts @@ -5,6 +5,7 @@ export const feriaSexualidad = { fecha_inicio: '2025-03-07T00:00:01', fecha_fin: '2025-03-18T23:59:59', id_tipo_cuestionario: 1, + evento: 'Feria de la Sexualidad', secciones: [ { titulo: 'Información Personal',