diff --git a/modules/mobileApp/routes/agendas.ts b/modules/mobileApp/routes/agendas.ts index b3666b7a47..7c2e511a5c 100644 --- a/modules/mobileApp/routes/agendas.ts +++ b/modules/mobileApp/routes/agendas.ts @@ -41,6 +41,7 @@ router.get('/agendasDisponibles', async (req: any, res, next) => { matchAgendas['bloques.restantesProgramados'] = { $gt: 0 }; matchAgendas['estado'] = 'publicada'; matchAgendas['dinamica'] = false; + matchAgendas['bloques.appMobile'] = true; if (reglas) { matchAgendas['$or'] = [ diff --git a/modules/turnos/controller/agenda.ts b/modules/turnos/controller/agenda.ts index 79cebe7e68..11e710aa80 100644 --- a/modules/turnos/controller/agenda.ts +++ b/modules/turnos/controller/agenda.ts @@ -119,6 +119,7 @@ export async function liberarTurno(req, data, turno) { data.sobreturnos.splice(index, 1); } else { // Liberación de turno if (!data.dinamica) { + const emitidoPor = turno.emitidoPor; turno.estado = 'disponible'; turno.paciente = null; turno.tipoPrestacion = null; @@ -171,6 +172,10 @@ export async function liberarTurno(req, data, turno) { } } + if (emitidoPor && await esVirtual(emitidoPor)) { + bloque.restantesMobile = (bloque.restantesMobile || 0) + cant; + } + const fechaActualizar = moment().startOf('day').add(2, 'days'); // actualizamos turnos de la agenda si la hora de inicio esta dentro de las proxmas 48hs if (moment(data.horaInicio).isBefore(fechaActualizar)) { diff --git a/modules/turnos/routes/agenda.ts b/modules/turnos/routes/agenda.ts index 8992d67b6a..97ee29d341 100644 --- a/modules/turnos/routes/agenda.ts +++ b/modules/turnos/routes/agenda.ts @@ -21,6 +21,23 @@ import { tipoPrestacion } from '../../../core/tm/schemas/tipoPrestacion'; const router = express.Router(); +// Rechaza bloques de teleconsulta con todo el cupo asignado a turnos mobile pero sin ningún canal de atención seleccionado +function validarBloquesInvisibles(bloques): string | null { + if (!bloques) { + return null; + } + for (const bloque of bloques) { + const cupoMobile = Number(bloque.cupoMobile) || 0; + const cantidadTurnos = Number(bloque.cantidadTurnos) || 0; + const tienePrestacionTeleconsulta = (bloque.tipoPrestaciones || []).some(tp => tp.teleConsulta); + if (cupoMobile > 0 && cupoMobile === cantidadTurnos && tienePrestacionTeleconsulta && !bloque.appMobile && !bloque.citasVirtuales) { + const horaInicio = bloque.horaInicio ? moment(bloque.horaInicio).format('DD/MM/YYYY HH:mm') : 'sin horario'; + return `No se puede guardar la agenda: el bloque de las ${horaInicio} es de teleconsulta, tiene todo el cupo asignado a turnos mobile y no se seleccionó ningún canal de atención (appMobile ni citasVirtuales)`; + } + } + return null; +} + // devuelve los 10 ultimos turnos del paciente router.get('/agenda/paciente/:idPaciente', (req, res, next) => { @@ -245,7 +262,6 @@ router.get('/agenda/:id?', async (req, res, next) => { if (req.query.tieneTurnosAsignados) { query.where('bloques.turnos.estado').equals('asignado'); } - if (req.query.turno) { query.where('bloques.turnos._id').equals(req.query.turno); } @@ -313,6 +329,11 @@ router.post('/agenda', async (req: any, res, next) => { return next(errorPrestaciones); } + const errorBloques = validarBloquesInvisibles(req.body.bloques); + if (errorBloques) { + return next(errorBloques); + } + const mensajesSolapamiento = await agendaCtrl.verificarSolapamiento(data); if (!mensajesSolapamiento.tipoError) { const dataSaved = await data.save(); @@ -407,6 +428,11 @@ router.put('/agenda/:id', async (req: any, res, next) => { return next(errorPrestaciones); } + const errorBloques = validarBloquesInvisibles(req.body.bloques); + if (errorBloques) { + return next(errorBloques); + } + const mensajesSolapamiento = await agendaCtrl.verificarSolapamiento(req.body); if (mensajesSolapamiento.tipoError) { objetoLog.err = mensajesSolapamiento; diff --git a/modules/turnos/schemas/bloque.ts b/modules/turnos/schemas/bloque.ts index 674acd0779..b072c00cb7 100644 --- a/modules/turnos/schemas/bloque.ts +++ b/modules/turnos/schemas/bloque.ts @@ -54,6 +54,14 @@ const bloqueSchema = new mongoose.Schema({ type: Number, default: 0 }, + citasVirtuales: { + type: Boolean, + default: false + }, + appMobile: { + type: Boolean, + default: false + }, restantesMobile: { type: Number, default: 0