Saltar a contenido

Convoca Shifts

Guía para administradores: gestión de turnos de voluntariado de un centro social.

Versión cubierta: 2.5.26 · WP: 6.4+ · PHP: 8.1+ · Requiere: convoca-core y convoca-members activos.


Manual para la junta directiva (sin conocimientos técnicos)

Esta página es la referencia técnica del plugin. Para el día a día hay un manual en tres partes, en castellano y con capturas:

1. Introducción

Convoca Shifts gestiona los turnos de apertura de un centro social o asociación. Cubre el ciclo completo: creación de turnos, calendario visual (FullCalendar), auto-apuntado de voluntarios, control de asistencia, sincronización de horas con Convoca Members y exportación CSV.

Concepto clave: el tipo de contenido real es centro_turno (no turno). Los menús, shortcodes y la API usan "turnos" como nombre amigable.

Dependencias:

Plugin Rol Consecuencia si falta
convoca-core Utilidades, licencias, logger, Upgrade_Manager El plugin no carga (aviso en admin y retorno)
convoca-members Las personas asignables (voluntarios aprobados y monitores), CPT registro_hora, certificados Sin él no hay a quién asignar ni horas que acreditar: los selectores salen vacíos y la pantalla lo explica

Al activarse, el plugin registra el CPT, crea la tabla de registro de actividad y programa el cron. No crea roles ni toca capacidades: el vocabulario de personas es de Convoca Core y quién es voluntario o monitor lo aporta Convoca Members por el contrato convoca_shifts_personas_asignables.

Listado de turnos (Turnos Centro)

2. Modelo de datos

2.1. Estados del turno (_estado)

Valor Visual Significado
abierto_disponible 🟡 Pendiente Turno abierto, sin cubrir (o cubierto si tiene responsable)
abierto_ocupado 🔵 Ocupado Actividad interna; no inscribible por voluntarios
cerrado 🔴 Cerrado Festivo / sin apertura

2.2. Estado de asistencia (_estado_real)

Independiente del estado del turno; solo tiene sentido cuando hay responsable asignado.

Valor Visual
pendiente ⏳ Pendiente
realizado ✅ Realizado
no_asistio ❌ No asistió
justificada 📝 Ausencia justificada
cancelada_aviso 🔔 Ausencia avisada con antelación

Los estados justificada y cancelada_aviso no cuentan como falta (ver §7.4).

2.3. Meta keys del turno

Meta Tipo Descripción
_hora_fin string Hora de fin del turno
_estado string Estado del turno (ver 2.1)
_id_responsable integer ID del usuario responsable (0 = sin asignar)
_estado_real string Asistencia (ver 2.2)
_necesita_apoyo boolean El turno necesita acompañamiento (p. ej. sin llaves)
_notas string Notas libres
_monitor integer ID del usuario con rol monitor_actividad
_actividad string (legacy) nombre de actividad
_fecha_inicio string Fecha real de inicio usada por consultas y la API; si no existe, se usa post_date como respaldo
_convoca_shifts_horas_contabilizadas float Horas ya sumadas al voluntario en Members (evita doble conteo)
_convoca_shifts_reminder_sent integer Marca de recordatorio enviado
_convoca_fecha_aviso string Fecha del aviso de ausencia (estados justificada/cancelada_aviso)
_convoca_ausencia_motivo string Motivo de la ausencia justificada

La fecha/hora de inicio vive en post_date; el título del turno se regenera automáticamente al guardar según el estado y el responsable (convoca_shifts_sync_turno_on_save): 🔴 Centro Cerrado / 🔵 {actividad} / 🟢 Cubierto - {nombre} / 🟡 Pendiente. Un turno con fecha futura se fuerza a publish para que no caiga en estado "Programado".

2.4. Taxonomía

  • convoca_shifts_actividad (Actividades, jerárquica): clasifica los turnos "ocupados". Cada término admite una meta convoca_shifts_url_info (enlace a la entrada del blog con información e inscripciones). Se gestiona desde el menú lateral del CPT.

3. Menús de administración

Todos los submenús cuelgan del CPT Turnos Centro (centro_turno).

Menú Slug Capacidad Descripción
Añadir Turno Rápido convoca_shifts_turno_rapido convoca_shifts_manage_turnos Creación rápida con mini-calendario (sustituye al editor estándar)
Generar Turnos convoca_shifts_generar_turnos convoca_shifts_manage_turnos Duplicar semana, crear semana tipo, exportar CSV
Gestionar Voluntarios convoca_shifts_voluntarios_pendientes convoca_shifts_manage_turnos Aprobar / revocar voluntarios
Estadísticas convoca_shifts_estadisticas convoca_shifts_view_stats Tabla de actividad + registro de actividad
Auditoría Horas convoca_shifts_auditoria_horas convoca_shifts_audit_horas Recalcular horas acumuladas
Ajustes convoca_shifts_settings manage_inscripciones Ajustes + pestaña Estado
Estado convoca_shifts_status manage_options Diagnóstico del sistema

El listado de turnos es una tabla personalizada (WP_List_Table); la URL nativa edit.php?post_type=centro_turno redirige a ella. La edición usa un editor propio (convoca-shifts-editar-turno, página oculta del menú).

Capacidades y roles relevantes:

Capacidad Quién la tiene Para qué
gestionar_mis_turnos voluntarios aprobados Apuntarse/desapuntarse, crear turnos básicos
convoca_shifts_manage_turnos administradores Gestionar turnos
convoca_shifts_view_stats — Ver estadísticas
convoca_shifts_audit_horas — Auditoría de horas
manage_inscripciones — Acceder a Ajustes

Roles: voluntario_aprobado y monitor_actividad, creados por Convoca Core. Shifts no los crea ni los modifica: pide la lista de personas al contrato y sólo asigna a quien esté en ella.

4. Crear turnos

4.1. Añadir Turno Rápido

  1. Ve a Turnos Centro → Añadir Turno Rápido.
  2. Haz clic en un día del mini-calendario (solo hoy o días futuros).
  3. Elige horario: presets ☀️ Mañana (10-13h) / 🌇 Tarde (17-20h) o ⚙️ Personalizado.
  4. Estado inicial, opcional 🛟 "Necesita apoyo".
  5. Guardar Turno.

4.2. Editor de turno

Desde el listado, botón Editar. Campos: fecha, hora inicio, hora fin, responsable (solo voluntarios aprobados), estado del centro, actividad + monitor/a (solo si estado = ocupado), "Necesita apoyo" y estado de asistencia.

El horario se restringe al horario del centro (ver §12): los turnos fuera de rango se ajustan automáticamente.

5. Listado, filtros y acciones

El listado muestra columnas: Fecha, Horario, Estado, Responsable, Apoyo, Asistencia y Acciones.

  • Filtros: estado, asistencia y apoyo.
  • Búsqueda por texto.
  • Acciones en bloque: ✅ Marcar Realizado / ❌ Marcar No asistió.
  • Marcar asistencia dispara la sincronización de horas (ver §7).

6. Asignación y auto-apuntado

6.1. Cómo se apunta un voluntario

  1. El voluntario inicia sesión y ve el calendario ([convoca_calendario]).
  2. Solo puede apuntarse a turnos con estado abierto_disponible.
  3. No puede apuntarse a turnos ya pasados (usa _fecha_inicio, no post_date).
  4. El sistema comprueba solapamientos: si el voluntario ya tiene otro turno que se solapa en el horario, rechaza la asignación (convoca_shifts_check_user_overlap).
  5. La asignación es atómica (transacción + FOR UPDATE + UPDATE/INSERT) para evitar carreras entre dos voluntarios; si alguien se adelantó, responde 409 "Alguien se ha adelantado".

Al cubrirse, el título pasa a "🟢 Cubierto - {nombre}", se registra la actividad turno_cubierto y se notifica por correo al administrador del sitio.

6.2. Desapuntarse

El responsable (o un administrador) puede liberar el turno. El título vuelve a "🟡 Pendiente" y el estado a abierto_disponible. Un turno cerrado no se puede liberar por el frontend.

6.3. Apuntarse al próximo

El shortcode [convoca_boton_apuntarse] y la API /turnos/apuntarse-proximo seleccionan automáticamente el siguiente turno libre (estado disponible, sin responsable y con fecha futura), comprobando también solapamientos.

7. Asistencia y sincronización de horas

7.1. Flujo

Cuando un turno con responsable se marca como realizado, Hour_Sync:

  1. Calcula las horas entre _fecha_inicio y _hora_fin.
  2. Suma las horas a la meta del usuario _convoca_horas_voluntariado_total (UPSERT atómico).
  3. Guarda _convoca_shifts_horas_contabilizadas en el turno (evita doble conteo).
  4. Crea una entrada en el CPT registro_hora (de Convoca Members) con estado aprobada, enlazada al socio vía _convoca_member_id.

Si el estado pasa de realizado a otra cosa, se restan las horas y se elimina la marca.

7.2. Fix E2E-11: enlace canónico _convoca_member_id

Históricamente el registro se escribía con la clave _convoca_miembro_id (con "i"), que Voluntariado_Manager y Certificate_Generator de Members no leen. Resultado: las horas de turnos no se acumulaban al voluntario ni aparecían en el certificado.

En 2.5.2:

  • Hour_Sync escribe la clave canónica _convoca_member_id.
  • La migración upgrade_to_2_5_2_member_meta_key (Upgrade Manager) renombra las filas históricas _convoca_miembro_id → _convoca_member_id al actualizar el plugin.

7.3. Hook público

Tras cada sincronización de horas (solo si hubo cambio), se dispara:

/**
 * @param int   $user_id    ID del voluntario.
 * @param float $diff_horas Horas sumadas (positivo) o restadas (negativo).
 */
do_action( 'convoca_after_horas_voluntario_actualizadas', $user_id, $diff_horas );

Nota interna: se dispara vía Convoca\Core\Utils::do_action('convoca_after_horas_voluntario_actualizadas', 'convoca_horas_voluntario_actualizadas', …) — permite que otros plugins se enganchen con un hook alternativo.

7.4. Ausencias y penalización suave (No-Show)

Cuando un turno queda sin asistencia (no_asistio), el include No_Show_Manager.php registra una falta sin justificar en el contador del voluntario (user meta _convoca_no_shows, mapa turno→fecha, idempotente por turno) con una ventana móvil de 90 días (opción convoca_shifts_ventana_dias).

Opción Default Descripción
convoca_shifts_ventana_dias 90 Ventana móvil (días) para contar las faltas
convoca_shifts_aviso_socio_en 2 Faltas en la ventana para avisar al voluntario por email
convoca_shifts_aviso_admin_cada 3 Cada N faltas se avisa al administrador
  • Al alcanzar el umbral (convoca_shifts_aviso_socio_en) se envía un email automático al voluntario.
  • Cada N faltas (convoca_shifts_aviso_admin_cada) se avisa al administrador.
  • Sin bloqueos ni pérdida de puntos.
  • Las faltas sin justificar NO suman horas.

Filtros: convoca_shifts_no_show_email_socio y convoca_shifts_no_show_email_admin.

7.5. Ausencia justificada

El estado del turno se amplía con dos estados de ausencia que NO cuentan como falta en el contador de §7.4 (al justificar se limpia el registro):

Estado Significado
justificada Ausencia justificada
cancelada_aviso Ausencia avisada con antelación

Metas asociadas: _convoca_fecha_aviso (fecha del aviso) y _convoca_ausencia_motivo (motivo).

Flujo admin: selector de estado + fecha de aviso + motivo en el editor de turno, quick edit, acciones masivas «Marcar justificada» / «Marcar cancelada con aviso», y badges/filtros en el listado.

8. Generar turnos

Acceso: Turnos Centro → Generar Turnos.

8.1. Duplicar semana anterior

Copia todos los turnos de los últimos 7 días y los reprograma exactamente una semana después. Detalles de comportamiento:

  • Se conserva el estado original (un cerrado sigue cerrado).
  • No se copia el responsable (los nuevos quedan sin asignar).
  • Se omiten duplicados (si ya existe un turno en la misma fecha+hora).
  • El horario se re-ajusta al horario del centro.
  • Se ejecuta con bloqueo y transacción; borra la caché del resumen.

8.2. Crear semana tipo

Elige la fecha del lunes y configura por día: activo, hora inicio/fin, estado, actividad y monitor/a (si es "ocupado"), y "necesita apoyo". Genera los turnos omitiendo duplicados.

8.3. Exportar historial a CSV

Botón Exportar historial a CSV (en la misma página). Exporta todos los turnos publicados (sin selector de rango ni de columnas). Columnas: ID, Título, Fecha Inicio, Fecha Fin, Estado, Responsable, Necesita Apoyo, Asistencia, Notas. Incluye BOM UTF-8 para Excel.

Hay una segunda exportación en Estadísticas → Exportar Estadísticas a CSV (horas por voluntario), con protección anti inyección de fórmulas.

9. Gestión de voluntarios

Acceso: Turnos Centro → Gestionar Voluntarios.

  • Aprobar: cambia el rol del usuario a voluntario_aprobado, envía un correo de confirmación (con adjuntos vía filtro convoca_voluntario_aprobado_attachments) y dispara el hook convoca_voluntario_aprobado.
  • Revocar: cambia el rol a subscriber, marca la meta _convoca_shifts_aprobado = -1 y libera los turnos futuros asignados a ese voluntario (los deja pendientes). No puedes revocarte a ti mismo.

10. Estadísticas y auditoría de horas

  • Estadísticas: tabla por voluntario (turnos totales, realizados, faltas, horas aprobadas, último turno) + registro de actividad reciente paginado. Las horas se calculan con consultas agregadas SQL (evita N+1).
  • Auditoría Horas: muestra _convoca_horas_voluntariado_total frente a los turnos realizado de cada usuario, con botón Recalcular que re-escanea los turnos y reescribe el contador.

Registro de actividad: tabla {prefix}convoca_shifts_activity_log. Acciones registradas: turno_creado, turno_actualizado, turno_cubierto, turno_liberado, turno_asignado, turno_desasignado, asistencia_ok, asistencia_no, voluntario_aprobado, voluntario_revocado, conflicto_horario_detectado, log_debug_conflict.

11. Shortcodes, bloques y widgets

11.1. Shortcodes (registrados)

[convoca_calendario]                    Calendario FullCalendar (sin atributos)
[convoca_proximos_turnos cantidad="5"]  Lista de próximos turnos
[convoca_resumen_turnos semana="this"]  Resumen semanal (semana="this" | "next")
[convoca_boton_apuntarse]               Botón "Me apunto al siguiente turno libre"

Atributos reales: cantidad (próximos turnos) y semana (resumen). No existen los atributos vista ni categoria.

11.2. Bloques de Gutenberg

Bloque Descripción
centro-social/calendario Calendario interactivo
centro-social/proximos-turnos Próximos turnos (atributo cantidad, default 5)
centro-social/resumen Resumen semanal
centro-social/boton-apuntarse Botón de apuntado rápido

11.3. Widgets clásicos

CST: Calendario, CST: Próximos Turnos (con campo "cantidad"), CST: Resumen Semanal, CST: Botón Apuntarse.

Los assets se cargan solo cuando la página contiene un bloque/shortcode/widget del plugin (filtro convoca_shifts_force_enqueue_assets para forzarlo).

12. Ajustes y Estado del sistema

Acceso: Turnos Centro → Ajustes.

Opción Default Descripción
convoca_shifts_calendar_page_url — URL de la página con el calendario
convoca_shifts_hora_apertura 09:00 Hora de apertura del centro (límite inferior)
convoca_shifts_hora_cierre 22:00 Hora de cierre del centro (límite superior)
convoca_shifts_access_page_url # Enlace "Ir a Acceso" para usuarios no logueados

El horario del centro restringe la creación de turnos en todas las vías (rápido, semana tipo, duplicar, frontend, REST).

Estado del sistema comprueba: versión de PHP (mín. 8.0), existencia de la página de calendario con su shortcode, tablas compartidas de Core (convoca_logs, convoca_locks) y eventos cron programados.

13. Cron y recordatorios

Evento Frecuencia Función
convoca_shifts_hourly_event cada hora Envía recordatorio por correo al responsable de turnos que empiezan en ≤2 h (con responsable, no cerrados, no enviado aún)
convoca_shifts_daily_event diario Limpia la meta _convoca_shifts_reminder_sent de turnos con >2 días

Ambos se programan al activar y se limpian al desactivar/desinstalar.

14. API REST

Namespace: convoca-shifts/v1.

Método Ruta Acceso Descripción
GET /turnos público Lista de eventos (parámetros start, end)
GET /turnos/proximo-libre público Próximo turno sin cubrir
POST /turnos/{id}/apuntarse gestionar_mis_turnos o manage_options Inscribirse en un turno
POST /turnos/{id}/desapuntarse ídem Liberar el turno
POST /turnos/apuntarse-proximo ídem Inscribirse en el próximo libre
POST /turnos/crear ídem Crear turno (parámetros date, h_start, h_end, estado, apoyo)

Detalles:

  • Todas las rutas de escritura aplican rate limiting (check_rate_limit).
  • Crear turno desde el frontend: los no administradores solo pueden crear abierto_disponible y no en fechas pasadas.
  • /turnos/crear y /turnos/apuntarse devuelven errores tipados (not_found, not_available, past_turno, conflicto_horario, ya_cubierto, no_disponible, etc.).

15. Hooks públicos

Hook Tipo Cuándo
convoca_after_horas_voluntario_actualizadas action Tras sumar/restar horas al voluntario ($user_id, $diff_horas)
convoca_horas_voluntario_actualizadas action Hook alternativo gestionado por Convoca\Core\Utils::do_action
convoca_voluntario_aprobado action Al aprobar un voluntario ($user_id)
convoca_voluntario_aprobado_attachments filter Adjuntos del correo de aprobación
convoca_shifts_confirm_signup filter true para mostrar confirmación antes de apuntarse
convoca_shifts_force_enqueue_assets filter Forzar carga de assets del frontend
convoca_shifts_no_show_email_socio filter Email del aviso de faltas al voluntario
convoca_shifts_no_show_email_admin filter Email del aviso de faltas al administrador

16. Calidad y CI

El repositorio ejecuta cuatro jobs de CI (.github/workflows/ci.yml):

  • PHPCS (bloqueante): phpcs --standard=.phpcs.xml.dist con ignore_warnings_on_exit 1; cualquier error rompe el build.
  • PHPStan nivel 5, sin baseline: las excepciones legítimas se declaran inline en phpstan.neon.dist (ignoreErrors), no en un archivo de baseline.
  • PHPUnit: suite unitaria en PHP 8.2 y 8.3.
  • Plugin Check (PCP): categorías plugin_repo + security, con 0 errores (los warnings no fallan). Las consultas SQL directas usan %i para nombres de tabla y literales inline en prepare().

17. Desinstalación

Al desinstalar se eliminan los posts centro_turno, los términos de convoca_shifts_actividad, opciones, transients, cron y la tabla de actividad. Para conservar los datos (p. ej. desactivación temporal), define en wp-config.php:

define( 'CONVOCA_KEEP_DATA_ON_UNINSTALL', true );

La meta de usuario con prefijo _convoca_shifts_ (aprobado, teléfono, motivación) pertenece a Convoca Members y no se borra aquí.

18. Problemas comunes

Problema Causa probable / Solución
Turno no aparece en el calendario Verifica que esté publish (no papelera) y dentro del rango de fechas consultado
"Página Calendario no encontrada" en Estado El diagnóstico busca una página con [calendario_centro]; crea la página con ese shortcode o revisa §11
Horas no se acumulan al voluntario Convoca Members inactivo, o datos anteriores a 2.5.2 sin migrar (ver §7.2); usa "Recalcular" en Auditoría Horas
No puedo marcar "realizado" El turno debe tener responsable asignado
Apuntarse da "conflicto de horario" El voluntario ya tiene otro turno solapado
Turno futuro aparece como "Programado" El plugin fuerza publish al guardar; si persiste, guarda el turno de nuevo
No hay submenús visibles Verifica que tu rol tiene las capacidades de §3