cuestionario contestado, respuestas guardadas
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags, getSchemaPath } from '@nestjs/swagger';
|
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags, getSchemaPath } from '@nestjs/swagger';
|
||||||
import { feriaSexualidad } from '../../utils/crear_formulario_feria';
|
import { feriaSexualidad } from '../../utils/crear_formulario_feria';
|
||||||
import { applyDecorators } from '@nestjs/common';
|
import { applyDecorators } from '@nestjs/common';
|
||||||
import { FormularioDto } from './dto/formulario.schema';
|
import { FormularioDto, FormularioFeriaSchema } from './dto/formulario.schema';
|
||||||
|
|
||||||
export class CuestionarioApiDocumentation {
|
export class CuestionarioApiDocumentation {
|
||||||
// Decoradores para toda la clase del controlador
|
// Decoradores para toda la clase del controlador
|
||||||
|
|||||||
@@ -79,15 +79,22 @@ export class CuestionarioService {
|
|||||||
for (let j = 0; j < seccionDto.preguntas.length; j++) {
|
for (let j = 0; j < seccionDto.preguntas.length; j++) {
|
||||||
const preguntaDto = seccionDto.preguntas[j];
|
const preguntaDto = seccionDto.preguntas[j];
|
||||||
|
|
||||||
// Obtener el tipo de pregunta por su nombre
|
// Mapear directamente el tipo de pregunta a su ID correspondiente
|
||||||
const tipoPregunta = await queryRunner.manager.findOne(TipoPregunta, {
|
let idTipoPregunta = 7; // Valor por defecto (desconocido)
|
||||||
where: { tipo_pregunta: preguntaDto.tipo },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!tipoPregunta) {
|
// Mapeamos el tipo de pregunta a su ID correspondiente
|
||||||
throw new Error(`Tipo de pregunta '${preguntaDto.tipo}' no encontrado`);
|
if (preguntaDto.tipo === 'Cerrada') {
|
||||||
|
idTipoPregunta = 1;
|
||||||
|
} else if (preguntaDto.tipo === 'Abierta') {
|
||||||
|
idTipoPregunta = 2;
|
||||||
|
} else if (preguntaDto.tipo === 'Multiple') {
|
||||||
|
idTipoPregunta = 3;
|
||||||
|
} else {
|
||||||
|
console.warn(`Tipo de pregunta no reconocido: ${preguntaDto.tipo}. Se asignará como desconocido.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tipoPregunta = { id_tipo: idTipoPregunta, tipo_pregunta: preguntaDto.tipo };
|
||||||
|
|
||||||
// Crear pregunta
|
// Crear pregunta
|
||||||
const pregunta = new Pregunta();
|
const pregunta = new Pregunta();
|
||||||
pregunta.pregunta = preguntaDto.titulo;
|
pregunta.pregunta = preguntaDto.titulo;
|
||||||
@@ -179,6 +186,13 @@ export class CuestionarioService {
|
|||||||
tipo_cuestionario: 'Encuesta'
|
tipo_cuestionario: 'Encuesta'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Mapeador de ID de tipo de pregunta a nombres conocidos
|
||||||
|
const tiposPreguntaMap = {
|
||||||
|
1: { id_tipo: 1, tipo_pregunta: 'Cerrada' },
|
||||||
|
2: { id_tipo: 2, tipo_pregunta: 'Abierta' },
|
||||||
|
3: { id_tipo: 3, tipo_pregunta: 'Multiple' }
|
||||||
|
};
|
||||||
|
|
||||||
// Obtener las relaciones cuestionario-seccion
|
// Obtener las relaciones cuestionario-seccion
|
||||||
const cuestionarioSecciones = await this.cuestionarioSeccionRepository.find({
|
const cuestionarioSecciones = await this.cuestionarioSeccionRepository.find({
|
||||||
where: { id_cuestionario: id },
|
where: { id_cuestionario: id },
|
||||||
@@ -216,14 +230,8 @@ export class CuestionarioService {
|
|||||||
|
|
||||||
if (!pregunta) return null;
|
if (!pregunta) return null;
|
||||||
|
|
||||||
// Usar un mapeo hardcodeado para tipos de pregunta
|
// Usar el mapeo de tipos de pregunta definido arriba
|
||||||
const tiposPregunta = {
|
const tipoPregunta = tiposPreguntaMap[pregunta.id_tipo_pregunta] ||
|
||||||
1: { id_tipo: 1, tipo_pregunta: 'Cerrada' },
|
|
||||||
2: { id_tipo: 2, tipo_pregunta: 'Abierta' },
|
|
||||||
3: { id_tipo: 3, tipo_pregunta: 'Multiple' }
|
|
||||||
};
|
|
||||||
|
|
||||||
const tipoPregunta = tiposPregunta[pregunta.id_tipo_pregunta] ||
|
|
||||||
{ id_tipo: pregunta.id_tipo_pregunta, tipo_pregunta: 'Desconocido' };
|
{ id_tipo: pregunta.id_tipo_pregunta, tipo_pregunta: 'Desconocido' };
|
||||||
|
|
||||||
// Obtener opciones para preguntas de tipo multiple/radio
|
// Obtener opciones para preguntas de tipo multiple/radio
|
||||||
|
|||||||
@@ -1,94 +1,198 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { TipoPreguntaEnum } from '../../pregunta/dto/create-pregunta.dto';
|
||||||
|
|
||||||
export class OpcionDto {
|
// Ejemplo de respuesta de cuestionario completo
|
||||||
@ApiProperty({
|
export const FormularioFeriaSchema = {
|
||||||
description: 'Valor de la opción',
|
tipo_cuestionario: {
|
||||||
example: 'Si'
|
id_tipo_cuestionario: 1,
|
||||||
})
|
tipo_cuestionario: 'Encuesta'
|
||||||
valor: string;
|
},
|
||||||
}
|
cuestionario: {
|
||||||
|
id_cuestionario: 10,
|
||||||
export class PreguntaDto {
|
nombre_form: 'Registro para la Feria de la Sexualidad - Comunidad FES Acatlán',
|
||||||
@ApiProperty({
|
contador_secciones: 2,
|
||||||
description: 'Título de la pregunta',
|
descripcion: 'La Feria de la Sexualidad es un espacio seguro e informativo dirigido a toda la comunidad universitaria. Este registro nos ayudará a organizar mejor las actividades, talleres y charlas, así como conocer tus intereses. Por favor, completa el siguiente formulario para confirmar tu participación.',
|
||||||
example: '¿Eres parte de la comunidad de la FES Acatlán?'
|
editable: true,
|
||||||
})
|
fecha_inicio: '2025-03-26T00:00:00',
|
||||||
titulo: string;
|
fecha_fin: '2025-03-31T23:59:59',
|
||||||
|
id_cuestionario_original: null,
|
||||||
@ApiProperty({
|
id_tipo_cuestionario: 1,
|
||||||
description: 'Indica si la pregunta es obligatoria',
|
secciones: [
|
||||||
example: true
|
{
|
||||||
})
|
id_cuestionario_seccion: 1,
|
||||||
obligatoria: boolean;
|
posicion: 1,
|
||||||
|
seccion: {
|
||||||
@ApiProperty({
|
id_seccion: 100,
|
||||||
description: 'Tipo de pregunta (Texto, Numero, Multiple, Radio, Abierto, Fecha)',
|
contador_pregunta: 2,
|
||||||
example: 'Multiple'
|
descripcion: 'Información básica',
|
||||||
})
|
titulo: 'Datos personales'
|
||||||
tipo: string;
|
},
|
||||||
|
preguntas: [
|
||||||
@ApiProperty({
|
{
|
||||||
description: 'Lista de opciones para preguntas de tipo Multiple o Radio',
|
id_seccion_pregunta: 1000,
|
||||||
type: [OpcionDto],
|
posicion: 1,
|
||||||
required: false
|
pregunta: {
|
||||||
})
|
id_pregunta: 101,
|
||||||
opciones?: OpcionDto[];
|
pregunta: '¿Eres parte de la comunidad de la FES Acatlán?',
|
||||||
}
|
contador_opcion: 2,
|
||||||
|
obligatoria: true,
|
||||||
export class SeccionDto {
|
id_tipo_pregunta: 1,
|
||||||
@ApiProperty({
|
id_opcion_dependiente: null,
|
||||||
description: 'Título de la sección',
|
tipo_pregunta: {
|
||||||
example: 'Información Personal'
|
id_tipo: 1,
|
||||||
})
|
tipo_pregunta: 'Cerrada'
|
||||||
titulo: string;
|
},
|
||||||
|
opciones: [
|
||||||
@ApiProperty({
|
{
|
||||||
description: 'Descripción de la sección',
|
id_pregunta_opcion: 50001,
|
||||||
example: 'Proporciona tus datos personales para poder contactarte.'
|
posicion: 1,
|
||||||
})
|
id_opcion: 90001,
|
||||||
descripcion?: string;
|
opcion: {
|
||||||
|
id_opcion: 90001,
|
||||||
@ApiProperty({
|
opcion: 'Sí'
|
||||||
description: 'Lista de preguntas que conforman la sección',
|
}
|
||||||
type: [PreguntaDto]
|
},
|
||||||
})
|
{
|
||||||
preguntas: PreguntaDto[];
|
id_pregunta_opcion: 50002,
|
||||||
}
|
posicion: 2,
|
||||||
|
id_opcion: 90002,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90002,
|
||||||
|
opcion: 'No'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_seccion_pregunta: 1001,
|
||||||
|
posicion: 2,
|
||||||
|
pregunta: {
|
||||||
|
id_pregunta: 102,
|
||||||
|
pregunta: 'Número de cuenta (solo para estudiantes de la FES Acatlán)',
|
||||||
|
contador_opcion: 0,
|
||||||
|
obligatoria: false,
|
||||||
|
id_tipo_pregunta: 2,
|
||||||
|
id_opcion_dependiente: 90001, // Dependiente de la respuesta "Sí" en la pregunta anterior
|
||||||
|
tipo_pregunta: {
|
||||||
|
id_tipo: 2,
|
||||||
|
tipo_pregunta: 'Abierta'
|
||||||
|
},
|
||||||
|
opciones: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_cuestionario_seccion: 2,
|
||||||
|
posicion: 2,
|
||||||
|
seccion: {
|
||||||
|
id_seccion: 101,
|
||||||
|
contador_pregunta: 2,
|
||||||
|
descripcion: 'Información sobre tus intereses',
|
||||||
|
titulo: 'Intereses'
|
||||||
|
},
|
||||||
|
preguntas: [
|
||||||
|
{
|
||||||
|
id_seccion_pregunta: 1003,
|
||||||
|
posicion: 1,
|
||||||
|
pregunta: {
|
||||||
|
id_pregunta: 106,
|
||||||
|
pregunta: '¿Qué temas te interesan para la Feria de la Sexualidad?',
|
||||||
|
contador_opcion: 5,
|
||||||
|
obligatoria: true,
|
||||||
|
id_tipo_pregunta: 3,
|
||||||
|
id_opcion_dependiente: null,
|
||||||
|
tipo_pregunta: {
|
||||||
|
id_tipo: 3,
|
||||||
|
tipo_pregunta: 'Multiple'
|
||||||
|
},
|
||||||
|
opciones: [
|
||||||
|
{
|
||||||
|
id_pregunta_opcion: 50010,
|
||||||
|
posicion: 1,
|
||||||
|
id_opcion: 90010,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90010,
|
||||||
|
opcion: 'Educación sexual'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_pregunta_opcion: 50011,
|
||||||
|
posicion: 2,
|
||||||
|
id_opcion: 90011,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90011,
|
||||||
|
opcion: 'Prevención de ITS'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_pregunta_opcion: 50012,
|
||||||
|
posicion: 3,
|
||||||
|
id_opcion: 90012,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90012,
|
||||||
|
opcion: 'Salud reproductiva'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_pregunta_opcion: 50013,
|
||||||
|
posicion: 4,
|
||||||
|
id_opcion: 90013,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90013,
|
||||||
|
opcion: 'Diversidad sexual y de género'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_pregunta_opcion: 50014,
|
||||||
|
posicion: 5,
|
||||||
|
id_opcion: 90014,
|
||||||
|
opcion: {
|
||||||
|
id_opcion: 90014,
|
||||||
|
opcion: 'Relaciones saludables'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_seccion_pregunta: 1004,
|
||||||
|
posicion: 2,
|
||||||
|
pregunta: {
|
||||||
|
id_pregunta: 107,
|
||||||
|
pregunta: '¿Algún otro tema que te gustaría que se abordara?',
|
||||||
|
contador_opcion: 0,
|
||||||
|
obligatoria: false,
|
||||||
|
id_tipo_pregunta: 2,
|
||||||
|
id_opcion_dependiente: null,
|
||||||
|
tipo_pregunta: {
|
||||||
|
id_tipo: 2,
|
||||||
|
tipo_pregunta: 'Abierta'
|
||||||
|
},
|
||||||
|
opciones: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ejemplo de tipo FormularioDto para usar en la API
|
||||||
export class FormularioDto {
|
export class FormularioDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'Nombre del formulario',
|
description: 'Tipo de cuestionario',
|
||||||
example: 'Registro para la Feria de la Sexualidad - FES Acatlán'
|
example: {
|
||||||
|
id_tipo_cuestionario: 1,
|
||||||
|
tipo_cuestionario: 'Encuesta'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
nombre_form: string;
|
tipo_cuestionario: any;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'Descripción del formulario',
|
description: 'Información completa del cuestionario',
|
||||||
example: 'La Feria de la Sexualidad es un espacio seguro e informativo...'
|
example: FormularioFeriaSchema.cuestionario
|
||||||
})
|
})
|
||||||
descripcion?: string;
|
cuestionario: any;
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Fecha de inicio del formulario',
|
|
||||||
example: '2025-03-07T00:00:01'
|
|
||||||
})
|
|
||||||
fecha_inicio?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Fecha de fin del formulario',
|
|
||||||
example: '2025-03-18T23:59:59'
|
|
||||||
})
|
|
||||||
fecha_fin?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID del tipo de cuestionario',
|
|
||||||
example: 1
|
|
||||||
})
|
|
||||||
id_tipo_cuestionario: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Secciones que conforman el formulario',
|
|
||||||
type: [SeccionDto]
|
|
||||||
})
|
|
||||||
secciones: SeccionDto[];
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,11 @@ import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/commo
|
|||||||
import { CuestionarioRespondidoService } from './cuestionario_respondido.service';
|
import { CuestionarioRespondidoService } from './cuestionario_respondido.service';
|
||||||
import { CreateCuestionarioRespondidoDto } from './dto/create-cuestionario_respondido.dto';
|
import { CreateCuestionarioRespondidoDto } from './dto/create-cuestionario_respondido.dto';
|
||||||
import { UpdateCuestionarioRespondidoDto } from './dto/update-cuestionario_respondido.dto';
|
import { UpdateCuestionarioRespondidoDto } from './dto/update-cuestionario_respondido.dto';
|
||||||
|
import { SubmitRespuestasDto } from './dto/submit-respuestas.dto';
|
||||||
|
import { ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CuestionarioRespondidoApiDocumentation } from './cuestionario_respondido.documentation';
|
||||||
|
|
||||||
|
@ApiTags('Cuestionario Respondido')
|
||||||
@Controller('cuestionario-respondido')
|
@Controller('cuestionario-respondido')
|
||||||
export class CuestionarioRespondidoController {
|
export class CuestionarioRespondidoController {
|
||||||
constructor(private readonly cuestionarioRespondidoService: CuestionarioRespondidoService) {}
|
constructor(private readonly cuestionarioRespondidoService: CuestionarioRespondidoService) {}
|
||||||
@@ -12,6 +16,22 @@ export class CuestionarioRespondidoController {
|
|||||||
return this.cuestionarioRespondidoService.create(createCuestionarioRespondidoDto);
|
return this.cuestionarioRespondidoService.create(createCuestionarioRespondidoDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('submit')
|
||||||
|
@CuestionarioRespondidoApiDocumentation.ApiSubmitRespuestas
|
||||||
|
@ApiBody({
|
||||||
|
type: SubmitRespuestasDto,
|
||||||
|
examples: {
|
||||||
|
comunidad: CuestionarioRespondidoApiDocumentation.ApiSubmitRespuestasExamples.communityExample,
|
||||||
|
externos: CuestionarioRespondidoApiDocumentation.ApiSubmitRespuestasExamples.externalExample
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@CuestionarioRespondidoApiDocumentation.ApiSubmitResponse201
|
||||||
|
@CuestionarioRespondidoApiDocumentation.ApiSubmitResponse400
|
||||||
|
@CuestionarioRespondidoApiDocumentation.ApiSubmitResponse404
|
||||||
|
submitRespuestas(@Body() submitRespuestasDto: SubmitRespuestasDto) {
|
||||||
|
return this.cuestionarioRespondidoService.submitRespuestas(submitRespuestasDto);
|
||||||
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
findAll() {
|
findAll() {
|
||||||
return this.cuestionarioRespondidoService.findAll();
|
return this.cuestionarioRespondidoService.findAll();
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class CuestionarioRespondidoApiDocumentation {
|
||||||
|
static ApiController = ApiTags('Cuestionario Respondido');
|
||||||
|
|
||||||
|
static ApiSubmitRespuestas = ApiOperation({
|
||||||
|
summary: 'Enviar respuestas a un cuestionario',
|
||||||
|
description: 'Registra las respuestas de un participante a un cuestionario. Crea un registro de participante si no existe uno con ese correo.'
|
||||||
|
});
|
||||||
|
|
||||||
|
static ApiSubmitResponse201 = ApiResponse({
|
||||||
|
status: 201,
|
||||||
|
description: 'Respuestas guardadas correctamente',
|
||||||
|
schema: {
|
||||||
|
properties: {
|
||||||
|
success: { type: 'boolean', example: true },
|
||||||
|
message: { type: 'string', example: 'Respuestas guardadas correctamente' },
|
||||||
|
cuestionarioRespondidoId: { type: 'number', example: 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static ApiSubmitResponse400 = ApiResponse({
|
||||||
|
status: 400,
|
||||||
|
description: 'Datos inválidos en la solicitud',
|
||||||
|
schema: {
|
||||||
|
properties: {
|
||||||
|
statusCode: { type: 'number', example: 400 },
|
||||||
|
message: { type: 'string', example: 'No se encontró la opción \'Opción inválida\' para la pregunta 101' },
|
||||||
|
error: { type: 'string', example: 'Bad Request' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static ApiSubmitResponse404 = ApiResponse({
|
||||||
|
status: 404,
|
||||||
|
description: 'Cuestionario o pregunta no encontrada',
|
||||||
|
schema: {
|
||||||
|
properties: {
|
||||||
|
statusCode: { type: 'number', example: 404 },
|
||||||
|
message: { type: 'string', example: 'Cuestionario con ID 999 no encontrado' },
|
||||||
|
error: { type: 'string', example: 'Not Found' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static ApiSubmitRespuestasExamples = {
|
||||||
|
communityExample: {
|
||||||
|
summary: 'Ejemplo de respuesta para un miembro de la comunidad',
|
||||||
|
value: {
|
||||||
|
id_formulario: 1,
|
||||||
|
correo: 'estudiante@acatlan.unam.mx',
|
||||||
|
respuestas: [
|
||||||
|
{ id_pregunta: 101, valor: 'Si' }, // ¿Eres parte de la comunidad de la FES Acatlán?
|
||||||
|
{ id_pregunta: 102, valor: '123456789' }, // Numero de cuenta
|
||||||
|
{ id_pregunta: 106, valor: 'Prefiero no decirlo' } // Género
|
||||||
|
],
|
||||||
|
fecha_envio: '2025-04-02T13:45:00'
|
||||||
|
},
|
||||||
|
description: 'Datos de un estudiante de la FES Acatlán que proporciona su número de cuenta.'
|
||||||
|
},
|
||||||
|
externalExample: {
|
||||||
|
summary: 'Ejemplo de respuesta para un participante externo',
|
||||||
|
value: {
|
||||||
|
id_formulario: 1,
|
||||||
|
correo: 'externo@ejemplo.com',
|
||||||
|
respuestas: [
|
||||||
|
{ id_pregunta: 101, valor: 'No' }, // ¿Eres parte de la comunidad de la FES Acatlán?
|
||||||
|
{ id_pregunta: 103, valor: 'Juan Carlos' }, // Nombre(s)
|
||||||
|
{ id_pregunta: 104, valor: 'Ramírez López' }, // Apellidos
|
||||||
|
{ id_pregunta: 106, valor: 'Prefiero no decirlo' }, // Género
|
||||||
|
{ id_pregunta: 107, valor: 'UAM Azcapotzalco' } // Institución de procedencia
|
||||||
|
],
|
||||||
|
fecha_envio: '2025-04-02T13:45:00'
|
||||||
|
},
|
||||||
|
description: 'Datos de un participante externo que proporciona su nombre e institución de procedencia.'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,10 +5,26 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
|||||||
import { CuestionarioRespondido } from './entities/cuestionario_respondido.entity';
|
import { CuestionarioRespondido } from './entities/cuestionario_respondido.entity';
|
||||||
import { CuestionarioModule } from '../cuestionario/cuestionario.module';
|
import { CuestionarioModule } from '../cuestionario/cuestionario.module';
|
||||||
import { ParticipanteModule } from '../participante/participante.module';
|
import { ParticipanteModule } from '../participante/participante.module';
|
||||||
|
import { Participante } from '../participante/participante.entity';
|
||||||
|
import { Cuestionario } from '../cuestionario/entities/cuestionario.entity';
|
||||||
|
import { Pregunta } from '../pregunta/entities/pregunta.entity';
|
||||||
|
import { RespuestaParticipanteAbierta } from '../respuesta_participante_abierta/entities/respuesta_participante_abierta.entity';
|
||||||
|
import { RespuestaParticipanteCerrada } from '../respuesta_participante_cerrada/entities/respuesta_participante_cerrada.entity';
|
||||||
|
import { PreguntaOpcion } from '../pregunta_opcion/entities/pregunta_opcion.entity';
|
||||||
|
import { Opcion } from '../opcion/entities/opcion.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([CuestionarioRespondido]),
|
TypeOrmModule.forFeature([
|
||||||
|
CuestionarioRespondido,
|
||||||
|
Participante,
|
||||||
|
Cuestionario,
|
||||||
|
Pregunta,
|
||||||
|
RespuestaParticipanteAbierta,
|
||||||
|
RespuestaParticipanteCerrada,
|
||||||
|
PreguntaOpcion,
|
||||||
|
Opcion
|
||||||
|
]),
|
||||||
CuestionarioModule,
|
CuestionarioModule,
|
||||||
ParticipanteModule
|
ParticipanteModule
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,19 +1,181 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository, DataSource } from 'typeorm';
|
||||||
import { CreateCuestionarioRespondidoDto } from './dto/create-cuestionario_respondido.dto';
|
import { CreateCuestionarioRespondidoDto } from './dto/create-cuestionario_respondido.dto';
|
||||||
import { UpdateCuestionarioRespondidoDto } from './dto/update-cuestionario_respondido.dto';
|
import { UpdateCuestionarioRespondidoDto } from './dto/update-cuestionario_respondido.dto';
|
||||||
|
import { SubmitRespuestasDto } from './dto/submit-respuestas.dto';
|
||||||
|
import { CuestionarioRespondido } from './entities/cuestionario_respondido.entity';
|
||||||
|
import { Participante } from '../participante/participante.entity';
|
||||||
|
import { Cuestionario } from '../cuestionario/entities/cuestionario.entity';
|
||||||
|
import { Pregunta } from '../pregunta/entities/pregunta.entity';
|
||||||
|
import { RespuestaParticipanteAbierta } from '../respuesta_participante_abierta/entities/respuesta_participante_abierta.entity';
|
||||||
|
import { RespuestaParticipanteCerrada } from '../respuesta_participante_cerrada/entities/respuesta_participante_cerrada.entity';
|
||||||
|
import { PreguntaOpcion } from '../pregunta_opcion/entities/pregunta_opcion.entity';
|
||||||
|
import { Opcion } from '../opcion/entities/opcion.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CuestionarioRespondidoService {
|
export class CuestionarioRespondidoService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(CuestionarioRespondido)
|
||||||
|
private cuestionarioRespondidoRepository: Repository<CuestionarioRespondido>,
|
||||||
|
@InjectRepository(Participante)
|
||||||
|
private participanteRepository: Repository<Participante>,
|
||||||
|
@InjectRepository(Cuestionario)
|
||||||
|
private cuestionarioRepository: Repository<Cuestionario>,
|
||||||
|
@InjectRepository(Pregunta)
|
||||||
|
private preguntaRepository: Repository<Pregunta>,
|
||||||
|
@InjectRepository(RespuestaParticipanteAbierta)
|
||||||
|
private respuestaAbiertaRepository: Repository<RespuestaParticipanteAbierta>,
|
||||||
|
@InjectRepository(RespuestaParticipanteCerrada)
|
||||||
|
private respuestaCerradaRepository: Repository<RespuestaParticipanteCerrada>,
|
||||||
|
@InjectRepository(PreguntaOpcion)
|
||||||
|
private preguntaOpcionRepository: Repository<PreguntaOpcion>,
|
||||||
|
@InjectRepository(Opcion)
|
||||||
|
private opcionRepository: Repository<Opcion>,
|
||||||
|
private dataSource: DataSource,
|
||||||
|
) {}
|
||||||
|
|
||||||
create(createCuestionarioRespondidoDto: CreateCuestionarioRespondidoDto) {
|
create(createCuestionarioRespondidoDto: CreateCuestionarioRespondidoDto) {
|
||||||
return 'This action adds a new cuestionarioRespondido';
|
return 'This action adds a new cuestionarioRespondido';
|
||||||
}
|
}
|
||||||
|
|
||||||
findAll() {
|
async submitRespuestas(submitDto: SubmitRespuestasDto) {
|
||||||
return `This action returns all cuestionarioRespondido`;
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
await queryRunner.connect();
|
||||||
|
await queryRunner.startTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Verificar que el cuestionario existe
|
||||||
|
const cuestionario = await this.cuestionarioRepository.findOne({
|
||||||
|
where: { id_cuestionario: submitDto.id_formulario }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cuestionario) {
|
||||||
|
throw new NotFoundException(`Cuestionario con ID ${submitDto.id_formulario} no encontrado`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Buscar o crear participante
|
||||||
|
let participante = await this.participanteRepository.findOne({
|
||||||
|
where: { correo: submitDto.correo }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!participante) {
|
||||||
|
participante = new Participante();
|
||||||
|
participante.correo = submitDto.correo;
|
||||||
|
participante.id_tipo_user = 1; // Usar un tipo de usuario por defecto
|
||||||
|
participante = await queryRunner.manager.save(participante);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Crear un nuevo registro de cuestionario respondido
|
||||||
|
const cuestionarioRespondido = new CuestionarioRespondido();
|
||||||
|
cuestionarioRespondido.cuestionario = cuestionario;
|
||||||
|
cuestionarioRespondido.participante = participante;
|
||||||
|
cuestionarioRespondido.fechaRespuesta = submitDto.fecha_envio ?
|
||||||
|
new Date(submitDto.fecha_envio) : new Date();
|
||||||
|
|
||||||
|
const savedCuestionarioRespondido = await queryRunner.manager.save(cuestionarioRespondido);
|
||||||
|
|
||||||
|
// 4. Procesar cada respuesta
|
||||||
|
for (const respuestaDto of submitDto.respuestas) {
|
||||||
|
// Buscar la pregunta
|
||||||
|
const pregunta = await this.preguntaRepository.findOne({
|
||||||
|
where: { id_pregunta: respuestaDto.id_pregunta },
|
||||||
|
relations: ['tipoPregunta']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!pregunta) {
|
||||||
|
throw new NotFoundException(`Pregunta con ID ${respuestaDto.id_pregunta} no encontrada`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determinar tipo de pregunta por ID
|
||||||
|
const esPreguntaAbierta = pregunta.id_tipo_pregunta === 2;
|
||||||
|
|
||||||
|
// O determinar tipo de pregunta por su nombre si existe
|
||||||
|
const esPreguntaTipoAbierta = pregunta.tipoPregunta &&
|
||||||
|
pregunta.tipoPregunta.tipo_pregunta === 'Abierta';
|
||||||
|
|
||||||
|
// Determinar tipo de pregunta y guardar respuesta adecuadamente
|
||||||
|
if (esPreguntaAbierta || esPreguntaTipoAbierta) {
|
||||||
|
// Respuesta abierta (texto)
|
||||||
|
const respuestaAbierta = new RespuestaParticipanteAbierta();
|
||||||
|
respuestaAbierta.pregunta = pregunta;
|
||||||
|
respuestaAbierta.respuesta = respuestaDto.valor;
|
||||||
|
respuestaAbierta.cuestionarioRespondido = savedCuestionarioRespondido;
|
||||||
|
|
||||||
|
await queryRunner.manager.save(respuestaAbierta);
|
||||||
|
} else {
|
||||||
|
// Respuesta cerrada (opción)
|
||||||
|
// Buscar la opción correspondiente
|
||||||
|
const opciones = await this.opcionRepository.find({
|
||||||
|
where: { opcion: respuestaDto.valor }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opciones.length === 0) {
|
||||||
|
throw new BadRequestException(`No se encontró la opción '${respuestaDto.valor}' para la pregunta ${respuestaDto.id_pregunta}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buscar la relación entre pregunta y opción
|
||||||
|
const preguntaOpciones = await this.preguntaOpcionRepository
|
||||||
|
.createQueryBuilder('po')
|
||||||
|
.innerJoinAndSelect('po.opcion', 'opcion')
|
||||||
|
.where('po.id_pregunta = :preguntaId', { preguntaId: pregunta.id_pregunta })
|
||||||
|
.andWhere('opcion.id_opcion = :opcionId', { opcionId: opciones[0].id_opcion })
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
if (preguntaOpciones.length === 0) {
|
||||||
|
throw new BadRequestException(`La opción '${respuestaDto.valor}' no está asociada a la pregunta ${respuestaDto.id_pregunta}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guardar respuesta cerrada
|
||||||
|
const respuestaCerrada = new RespuestaParticipanteCerrada();
|
||||||
|
respuestaCerrada.preguntaOpcion = preguntaOpciones[0];
|
||||||
|
respuestaCerrada.cuestionarioRespondido = savedCuestionarioRespondido;
|
||||||
|
|
||||||
|
await queryRunner.manager.save(respuestaCerrada);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Respuestas guardadas correctamente',
|
||||||
|
cuestionarioRespondidoId: savedCuestionarioRespondido.idCuestionarioRespondido
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findOne(id: number) {
|
findAll() {
|
||||||
return `This action returns a #${id} cuestionarioRespondido`;
|
return this.cuestionarioRespondidoRepository.find({
|
||||||
|
relations: ['participante', 'cuestionario', 'respuestasAbiertas', 'respuestasCerradas']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOne(id: number) {
|
||||||
|
const cuestionarioRespondido = await this.cuestionarioRespondidoRepository.findOne({
|
||||||
|
where: { idCuestionarioRespondido: id },
|
||||||
|
relations: [
|
||||||
|
'participante',
|
||||||
|
'cuestionario',
|
||||||
|
'respuestasAbiertas',
|
||||||
|
'respuestasAbiertas.pregunta',
|
||||||
|
'respuestasCerradas',
|
||||||
|
'respuestasCerradas.preguntaOpcion',
|
||||||
|
'respuestasCerradas.preguntaOpcion.opcion',
|
||||||
|
'respuestasCerradas.preguntaOpcion.pregunta'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cuestionarioRespondido) {
|
||||||
|
throw new NotFoundException(`Cuestionario respondido con ID ${id} no encontrado`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cuestionarioRespondido;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: number, updateCuestionarioRespondidoDto: UpdateCuestionarioRespondidoDto) {
|
update(id: number, updateCuestionarioRespondidoDto: UpdateCuestionarioRespondidoDto) {
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsArray, IsDateString, IsNotEmpty, IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class RespuestaDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID de la pregunta respondida',
|
||||||
|
example: 101
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
id_pregunta: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Valor de la respuesta',
|
||||||
|
example: 'Si'
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
valor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SubmitRespuestasDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID del formulario a responder',
|
||||||
|
example: 1
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
id_formulario: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Correo electrónico del participante',
|
||||||
|
example: 'usuario@ejemplo.com'
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
correo: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Array de respuestas a las preguntas',
|
||||||
|
type: [RespuestaDto],
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
id_pregunta: 101,
|
||||||
|
valor: 'Si'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id_pregunta: 102,
|
||||||
|
valor: '123456789'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => RespuestaDto)
|
||||||
|
respuestas: RespuestaDto[];
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Fecha y hora del envío',
|
||||||
|
example: '2025-04-02T13:45:00'
|
||||||
|
})
|
||||||
|
@IsDateString()
|
||||||
|
@IsOptional()
|
||||||
|
fecha_envio?: string;
|
||||||
|
}
|
||||||
@@ -1,33 +1,93 @@
|
|||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsArray, IsBoolean, IsNotEmpty, IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator';
|
import { IsArray, IsBoolean, IsEnum, IsNotEmpty, IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export enum TipoPreguntaEnum {
|
||||||
|
CERRADA = 'Cerrada',
|
||||||
|
ABIERTA = 'Abierta',
|
||||||
|
MULTIPLE = 'Multiple'
|
||||||
|
}
|
||||||
|
|
||||||
export class OpcionDto {
|
export class OpcionDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Valor de la opción',
|
||||||
|
example: 'Sí'
|
||||||
|
})
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsString()
|
@IsString()
|
||||||
valor: string;
|
valor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreatePreguntaDto {
|
export class CreatePreguntaDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Título o texto de la pregunta',
|
||||||
|
example: '¿Eres parte de la comunidad de la FES Acatlán?'
|
||||||
|
})
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsString()
|
@IsString()
|
||||||
titulo: string;
|
titulo: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Indica si la pregunta es obligatoria',
|
||||||
|
example: true,
|
||||||
|
default: false
|
||||||
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
obligatoria?: boolean;
|
obligatoria?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tipo de pregunta',
|
||||||
|
enum: Object.values(TipoPreguntaEnum),
|
||||||
|
enumName: 'TipoPreguntaEnum',
|
||||||
|
example: TipoPreguntaEnum.CERRADA,
|
||||||
|
examples: {
|
||||||
|
'cerrada': {
|
||||||
|
summary: 'Pregunta de opción única',
|
||||||
|
value: TipoPreguntaEnum.CERRADA
|
||||||
|
},
|
||||||
|
'abierta': {
|
||||||
|
summary: 'Pregunta de texto libre',
|
||||||
|
value: TipoPreguntaEnum.ABIERTA
|
||||||
|
},
|
||||||
|
'multiple': {
|
||||||
|
summary: 'Pregunta de selección múltiple',
|
||||||
|
value: TipoPreguntaEnum.MULTIPLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsString()
|
@IsEnum(TipoPreguntaEnum, {
|
||||||
|
message: 'El tipo debe ser uno de los siguientes valores: Cerrada, Abierta, Multiple'
|
||||||
|
})
|
||||||
tipo: string;
|
tipo: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Contador de opciones (se calcula automáticamente)',
|
||||||
|
required: false
|
||||||
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
contador_opcion?: number;
|
contador_opcion?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID de la opción de la que depende esta pregunta (para preguntas condicionadas)',
|
||||||
|
required: false,
|
||||||
|
example: null
|
||||||
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
id_opcion_dependiente?: number;
|
id_opcion_dependiente?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Lista de opciones para preguntas de tipo Cerrada o Multiple',
|
||||||
|
type: [OpcionDto],
|
||||||
|
required: false,
|
||||||
|
examples: [
|
||||||
|
{ valor: 'Sí' },
|
||||||
|
{ valor: 'No' }
|
||||||
|
]
|
||||||
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { applyDecorators } from '@nestjs/common';
|
import { applyDecorators } from '@nestjs/common';
|
||||||
|
import { TipoPreguntaEnum } from './dto/create-pregunta.dto';
|
||||||
|
|
||||||
export class PreguntaApiDocumentation {
|
export class PreguntaApiDocumentation {
|
||||||
// Decoradores para toda la clase del controlador
|
// Decoradores para toda la clase del controlador
|
||||||
@@ -19,7 +20,12 @@ export class PreguntaApiDocumentation {
|
|||||||
properties: {
|
properties: {
|
||||||
titulo: { type: 'string', example: '¿Eres parte de la comunidad?' },
|
titulo: { type: 'string', example: '¿Eres parte de la comunidad?' },
|
||||||
obligatoria: { type: 'boolean', example: true },
|
obligatoria: { type: 'boolean', example: true },
|
||||||
tipo: { type: 'string', example: 'Multiple' },
|
tipo: {
|
||||||
|
type: 'string',
|
||||||
|
enum: Object.values(TipoPreguntaEnum),
|
||||||
|
description: 'Tipo de pregunta: Cerrada (opción única), Abierta (texto libre), Multiple (varias opciones)',
|
||||||
|
example: TipoPreguntaEnum.CERRADA
|
||||||
|
},
|
||||||
contador_opcion: { type: 'number', example: 0 },
|
contador_opcion: { type: 'number', example: 0 },
|
||||||
id_opcion_dependiente: { type: 'number', example: null },
|
id_opcion_dependiente: { type: 'number', example: null },
|
||||||
opciones: {
|
opciones: {
|
||||||
@@ -32,6 +38,41 @@ export class PreguntaApiDocumentation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
examples: {
|
||||||
|
cerrada: {
|
||||||
|
summary: 'Pregunta de opción única',
|
||||||
|
value: {
|
||||||
|
titulo: '¿Eres parte de la comunidad de la FES Acatlán?',
|
||||||
|
obligatoria: true,
|
||||||
|
tipo: TipoPreguntaEnum.CERRADA,
|
||||||
|
opciones: [
|
||||||
|
{ valor: 'Sí' },
|
||||||
|
{ valor: 'No' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
abierta: {
|
||||||
|
summary: 'Pregunta de texto libre',
|
||||||
|
value: {
|
||||||
|
titulo: '¿Qué mejorarías en nuestro servicio?',
|
||||||
|
obligatoria: false,
|
||||||
|
tipo: TipoPreguntaEnum.ABIERTA
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
summary: 'Pregunta de selección múltiple',
|
||||||
|
value: {
|
||||||
|
titulo: '¿Qué aspectos del servicio fueron de tu agrado?',
|
||||||
|
obligatoria: false,
|
||||||
|
tipo: TipoPreguntaEnum.MULTIPLE,
|
||||||
|
opciones: [
|
||||||
|
{ valor: 'Rapidez' },
|
||||||
|
{ valor: 'Atención al cliente' },
|
||||||
|
{ valor: 'Facilidad de uso' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
ApiResponse({
|
ApiResponse({
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ import { TipoPregunta } from './entities/tipo_pregunta.entity';
|
|||||||
imports: [TypeOrmModule.forFeature([TipoPregunta])],
|
imports: [TypeOrmModule.forFeature([TipoPregunta])],
|
||||||
controllers: [TipoPreguntaController],
|
controllers: [TipoPreguntaController],
|
||||||
providers: [TipoPreguntaService],
|
providers: [TipoPreguntaService],
|
||||||
exports: [TypeOrmModule]
|
exports: [TipoPreguntaService, TypeOrmModule]
|
||||||
})
|
})
|
||||||
export class TipoPreguntaModule {}
|
export class TipoPreguntaModule {}
|
||||||
|
|||||||
@@ -1,6 +1,59 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { CreateTipoPreguntaDto } from './dto/create-tipo_pregunta.dto';
|
||||||
|
import { UpdateTipoPreguntaDto } from './dto/update-tipo_pregunta.dto';
|
||||||
|
import { TipoPregunta } from './entities/tipo_pregunta.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TipoPreguntaService {
|
export class TipoPreguntaService implements OnModuleInit {
|
||||||
// Métodos del servicio
|
constructor(
|
||||||
|
@InjectRepository(TipoPregunta)
|
||||||
|
private tipoPreguntaRepository: Repository<TipoPregunta>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async onModuleInit() {
|
||||||
|
await this.seedTipoPreguntas();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async seedTipoPreguntas() {
|
||||||
|
const defaultTipos = [
|
||||||
|
{ tipo_pregunta: 'Cerrada' },
|
||||||
|
{ tipo_pregunta: 'Abierta' },
|
||||||
|
{ tipo_pregunta: 'Multiple' },
|
||||||
|
{ tipo_pregunta: 'Texto' }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const tipo of defaultTipos) {
|
||||||
|
const existingTipo = await this.tipoPreguntaRepository.findOne({
|
||||||
|
where: { tipo_pregunta: tipo.tipo_pregunta },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingTipo) {
|
||||||
|
await this.tipoPreguntaRepository.save(tipo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(createTipoPreguntaDto: CreateTipoPreguntaDto) {
|
||||||
|
return this.tipoPreguntaRepository.save(createTipoPreguntaDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll() {
|
||||||
|
return this.tipoPreguntaRepository.find();
|
||||||
|
}
|
||||||
|
|
||||||
|
findOne(id: number) {
|
||||||
|
return this.tipoPreguntaRepository.findOne({
|
||||||
|
where: { id_tipo: id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: number, updateTipoPreguntaDto: UpdateTipoPreguntaDto) {
|
||||||
|
return this.tipoPreguntaRepository.update(id, updateTipoPreguntaDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(id: number) {
|
||||||
|
return this.tipoPreguntaRepository.delete(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,29 +13,29 @@ export const feriaSexualidad = {
|
|||||||
preguntas: [
|
preguntas: [
|
||||||
{
|
{
|
||||||
titulo: '¿Eres parte de la comunidad de la FES Acatlán?',
|
titulo: '¿Eres parte de la comunidad de la FES Acatlán?',
|
||||||
tipo: 'Multiple',
|
tipo: 'Cerrada',
|
||||||
opciones: [{ valor: 'Si' }, { valor: 'No' }],
|
opciones: [{ valor: 'Si' }, { valor: 'No' }],
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
titulo: 'Numero de cuenta',
|
titulo: 'Numero de cuenta',
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
tipo: 'Numero',
|
tipo: 'Abierta',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
titulo: 'Nombre(s)',
|
titulo: 'Nombre(s)',
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
tipo: 'Texto',
|
tipo: 'Abierta',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
titulo: 'Apellidos',
|
titulo: 'Apellidos',
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
tipo: 'Texto',
|
tipo: 'Abierta',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
titulo: 'genero',
|
titulo: 'Género',
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
tipo: 'Radio',
|
tipo: 'Cerrada',
|
||||||
opciones: [
|
opciones: [
|
||||||
{ valor: 'Masculino' },
|
{ valor: 'Masculino' },
|
||||||
{ valor: 'Femenino' },
|
{ valor: 'Femenino' },
|
||||||
@@ -44,7 +44,7 @@ export const feriaSexualidad = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
titulo: 'Institución de procedencia',
|
titulo: 'Institución de procedencia',
|
||||||
tipo: 'Abierto',
|
tipo: 'Abierta',
|
||||||
obligatoria: true,
|
obligatoria: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user