diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..65a1965 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/src/cuestionario_respondido/cuestionario_respondido.service.ts b/src/cuestionario_respondido/cuestionario_respondido.service.ts index ab64aee..fdc1a1e 100644 --- a/src/cuestionario_respondido/cuestionario_respondido.service.ts +++ b/src/cuestionario_respondido/cuestionario_respondido.service.ts @@ -101,9 +101,80 @@ export class CuestionarioRespondidoService { ); if (cuestionarioRespondidoExistente) { await queryRunner.rollbackTransaction(); + + // Aunque ya haya respondido, enviamos el correo nuevamente + if (cuestionario && cuestionario.evento) { + try { + // Generar datos para el QR + const datosQR = { + id_participante: participante.id_participante, + id_evento: cuestionario.evento.id_evento, + id_cuestionario: cuestionario.id_cuestionario, + }; + + // Generar código QR + const qrJsonData = JSON.stringify(datosQR); + const qrBuffer = await QRCode.toBuffer(qrJsonData); + + // Enviar correo con el QR + const urlApiCorreos = process.env.url_api_correos; + + if (urlApiCorreos) { + await axios.post( + `${urlApiCorreos}/mail/send`, + { + to: participante.correo, + subject: `Evento: ${cuestionario.evento?.nombre_evento}`, + fecha_recibido: new Date().toISOString(), + html: generarHtmlCorreoAsistencia({ + nombreForm: cuestionario.nombre_form, + nombreEvento: cuestionario.evento?.nombre_evento, + correo: participante.correo, + fechaRegistro: new Date().toLocaleString(), + fechaInicioEvento: cuestionario.evento?.fecha_inicio + ? new Date( + cuestionario.evento.fecha_inicio, + ).toLocaleString() + : undefined, + fechaFinEvento: cuestionario.evento?.fecha_fin + ? new Date(cuestionario.evento.fecha_fin).toLocaleString() + : undefined, + }), + adjuntos: [ + { + filename: 'qr.png', + content: qrBuffer.toString('base64'), + encoding: 'base64', + cid: 'qrCode', + }, + ], + }, + { + headers: { + token: process.env.SYSTEM_TOKEN_API_CORREOS, + }, + }, + ); + + console.log( + `Correo reenviado exitosamente a ${participante.correo}`, + ); + } + } catch (error) { + console.error('Error al reenviar correo:', error); + } + } + return { - success: false, - message: `El participante con correo ${submitDto.correo} ya ha respondido el cuestionario ${cuestionario.nombre_form}.`, + success: true, + message: `El participante con correo ${submitDto.correo} ya había respondido el cuestionario ${cuestionario.nombre_form}. Se ha reenviado el correo con el código QR.`, + datos_qr: cuestionario.evento + ? { + id_participante: participante.id_participante, + id_evento: cuestionario.evento.id_evento, + id_cuestionario: cuestionario.id_cuestionario, + } + : undefined, }; } diff --git a/src/emails/registro-evento-ticket.ts b/src/emails/registro-evento-ticket.ts new file mode 100644 index 0000000..19a5814 --- /dev/null +++ b/src/emails/registro-evento-ticket.ts @@ -0,0 +1,307 @@ +export function generarHtmlCorreoAsistenciaTicket({ + nombreForm, + nombreEvento, + correo, + fechaRegistro, + fechaInicioEvento, + fechaFinEvento, +}: { + nombreForm: string; + nombreEvento: string; + correo: string; + fechaRegistro: string; + fechaInicioEvento?: string; + fechaFinEvento?: string; +}) { + const horarioEvento = + fechaInicioEvento && fechaFinEvento + ? `${fechaInicioEvento} al ${fechaFinEvento}` + : 'Por confirmar'; + + return ` +
+ +
+

¡Registro Confirmado!

+
+ + +
+ +
+

+ 🎓 ${nombreEvento || 'Evento Especial'} +

+

+ TICKET DE ENTRADA • ENTRADA GRATUITA +

+
+ + +
+
+ +
+
+ Código QR de Entrada +

+ ESCANEA PARA REGISTRAR ASISTENCIA +

+
+
+ + +
+
+

+ 📋 Detalles de tu registro +

+ +
+
+

+ Participante +

+

+ ${correo} +

+
+ +
+

+ Formulario +

+

+ ${nombreForm} +

+
+ +
+

+ Fecha de Registro +

+

+ ${fechaRegistro} +

+
+ +
+

+ 🕒 Horario del Evento +

+

+ ${horarioEvento} +

+
+
+
+
+
+
+ + +
+
+
+

+ IMPORTANTE: Presenta este código QR en la mesa + de registro +

+

+ Disponible en formato digital o impreso +

+
+
+

+ ENTRADA VÁLIDA +

+

+ ✓ Verificado +

+
+
+
+
+ + +
+

+ 📝 Instrucciones importantes: +

+ +
+ + +
+

+ Este mensaje fue enviado automáticamente. Por favor, no respondas a + este correo. +

+
+
+ `; +} diff --git a/src/evento/entities/evento.entity.ts b/src/evento/entities/evento.entity.ts index a86530e..d297f7e 100644 --- a/src/evento/entities/evento.entity.ts +++ b/src/evento/entities/evento.entity.ts @@ -1,10 +1,5 @@ import { Cuestionario } from 'src/cuestionario/entities/cuestionario.entity'; -import { - Column, - Entity, - OneToMany, - PrimaryGeneratedColumn, -} from 'typeorm'; +import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class Evento { diff --git a/src/evento/evento.service.ts b/src/evento/evento.service.ts index 9b86f9b..b7edb73 100644 --- a/src/evento/evento.service.ts +++ b/src/evento/evento.service.ts @@ -225,11 +225,19 @@ export class EventoService { async getEventosActivos() { const now = new Date(); - return this.eventoRepository.find({ + const eventos = await this.eventoRepository.find({ where: { fecha_fin: MoreThan(now), }, + relations: ['cuestionarios'], }); + + return eventos.map((evento) => ({ + ...evento, + total_cuestionarios: evento.cuestionarios + ? evento.cuestionarios.length + : 0, + })); } async getCuestionarioEvento(id_evento: number, id_cuestionario: number) {