diff --git a/src/cuestionario_respondido/cuestionario_respondido.service.ts b/src/cuestionario_respondido/cuestionario_respondido.service.ts index 6320b83..de9f5d1 100644 --- a/src/cuestionario_respondido/cuestionario_respondido.service.ts +++ b/src/cuestionario_respondido/cuestionario_respondido.service.ts @@ -400,72 +400,114 @@ recibas tu constancia.

throw new NotFoundException(`Cuestionario con ID ${idCuestionario} no encontrado`); } - // Obtener todas las respuestas para este cuestionario con sus relaciones - const respuestas = await this.dataSource.query(` + // Obtener todas las preguntas del cuestionario para los encabezados + const preguntas = await this.dataSource.query(` SELECT + p.id_pregunta, + p.pregunta, + p.id_tipo_pregunta + FROM pregunta p + JOIN seccion_pregunta sp ON p.id_pregunta = sp.id_pregunta + JOIN seccion s ON sp.id_seccion = s.id_seccion + JOIN cuestionario_seccion cs ON s.id_seccion = cs.id_seccion + WHERE cs.id_cuestionario = ? + ORDER BY sp.posicion, p.id_pregunta + `, [idCuestionario]); + + // Obtener los participantes que han respondido este cuestionario + const participantes = await this.dataSource.query(` + SELECT DISTINCT cr.id_cuestionario_respondido, cr.fecha_respuesta, p.id_participante, - p.correo AS correo_participante, - c.id_cuestionario, - c.nombre_form AS nombre_cuestionario, - e.id_evento, - e.nombre_evento, - preg.id_pregunta, - preg.pregunta, - -- Para respuestas abiertas - rpa.respuesta AS respuesta_abierta, - -- Para respuestas cerradas - o.id_opcion, - o.opcion AS respuesta_cerrada + p.correo AS correo_participante FROM cuestionario_respondido cr JOIN participante p ON cr.id_participante = p.id_participante - JOIN cuestionario c ON cr.id_cuestionario = c.id_cuestionario - LEFT JOIN evento e ON c.id_evento = e.id_evento - -- Respuestas abiertas - LEFT JOIN respuesta_participante_abierta rpa ON rpa.id_cuestionario_respondido = cr.id_cuestionario_respondido - LEFT JOIN pregunta preg_abierta ON rpa.id_pregunta = preg_abierta.id_pregunta - -- Respuestas cerradas - LEFT JOIN respuesta_participante_cerrada rpc ON rpc.id_cuestionario_respondido = cr.id_cuestionario_respondido - LEFT JOIN pregunta_opcion po ON rpc.id_pregunta_opcion = po.id_pregunta_opcion - LEFT JOIN pregunta preg ON po.id_pregunta = preg.id_pregunta - LEFT JOIN opcion o ON po.id_opcion = o.id_opcion - WHERE c.id_cuestionario = ? - ORDER BY cr.id_cuestionario_respondido, preg.id_pregunta + WHERE cr.id_cuestionario = ? + ORDER BY cr.fecha_respuesta DESC `, [idCuestionario]); + // Obtener todas las respuestas para este cuestionario + const respuestasAbiertas = await this.dataSource.query(` + SELECT + cr.id_cuestionario_respondido, + p.id_pregunta, + rpa.respuesta + FROM respuesta_participante_abierta rpa + JOIN pregunta p ON rpa.id_pregunta = p.id_pregunta + JOIN cuestionario_respondido cr ON rpa.id_cuestionario_respondido = cr.id_cuestionario_respondido + WHERE cr.id_cuestionario = ? + `, [idCuestionario]); + + const respuestasCerradas = await this.dataSource.query(` + SELECT + cr.id_cuestionario_respondido, + p.id_pregunta, + o.opcion + FROM respuesta_participante_cerrada rpc + JOIN pregunta_opcion po ON rpc.id_pregunta_opcion = po.id_pregunta_opcion + JOIN pregunta p ON po.id_pregunta = p.id_pregunta + JOIN opcion o ON po.id_opcion = o.id_opcion + JOIN cuestionario_respondido cr ON rpc.id_cuestionario_respondido = cr.id_cuestionario_respondido + WHERE cr.id_cuestionario = ? + `, [idCuestionario]); + + // Crear un mapa de respuestas por participante y pregunta + const respuestasPorParticipante = new Map(); + + // Agregar respuestas abiertas al mapa + respuestasAbiertas.forEach(respuesta => { + const key = `${respuesta.id_cuestionario_respondido}_${respuesta.id_pregunta}`; + respuestasPorParticipante.set(key, respuesta.respuesta); + }); + + // Agregar respuestas cerradas al mapa (posiblemente múltiples por pregunta) + respuestasCerradas.forEach(respuesta => { + const key = `${respuesta.id_cuestionario_respondido}_${respuesta.id_pregunta}`; + const respuestaActual = respuestasPorParticipante.get(key); + + if (respuestaActual) { + // Si ya hay una respuesta para esta pregunta, agregar esta opción + respuestasPorParticipante.set(key, `${respuestaActual}, ${respuesta.opcion}`); + } else { + respuestasPorParticipante.set(key, respuesta.opcion); + } + }); + // Preparar los datos para el CSV const datosReporte: string[][] = []; - // Agregar encabezados - const encabezados: string[] = [ - 'ID Respuesta', - 'Fecha Respuesta', + // Agregar encabezados con datos del participante seguidos por las preguntas + const encabezados = [ 'ID Participante', - 'Correo Participante', - 'Evento', - 'Cuestionario', - 'Pregunta', - 'Respuesta' + 'Correo', + 'Fecha Respuesta' ]; + // Agregar cada pregunta como un encabezado + preguntas.forEach(pregunta => { + encabezados.push(pregunta.pregunta); + }); + datosReporte.push(encabezados); - // Procesar los resultados para el CSV - for (const fila of respuestas) { - const respuesta = fila.respuesta_abierta || fila.respuesta_cerrada || ''; + // Crear una fila por cada participante + participantes.forEach(participante => { + const fila = [ + participante.id_participante.toString(), + participante.correo_participante, + new Date(participante.fecha_respuesta).toLocaleString() + ]; - datosReporte.push([ - fila.id_cuestionario_respondido?.toString() || '', - new Date(fila.fecha_respuesta).toLocaleString(), - fila.id_participante?.toString() || '', - fila.correo_participante || '', - fila.nombre_evento || 'Sin evento', - fila.nombre_cuestionario || '', - fila.pregunta || '', - respuesta - ]); - } + // Agregar cada respuesta en el orden de las preguntas + preguntas.forEach(pregunta => { + const key = `${participante.id_cuestionario_respondido}_${pregunta.id_pregunta}`; + const respuesta = respuestasPorParticipante.get(key) || ''; + fila.push(respuesta); + }); + + datosReporte.push(fila); + }); // Generar CSV de forma manual con valores separados por comas y líneas con saltos de línea // Escapar valores que contengan comas para evitar problemas con el formato CSV