Plugin para FacturaScripts que permite gestionar plataformas Moodle directamente desde el ERP. Conecta tu sistema de facturación con tu LMS mediante la API REST de Moodle.
El diagrama muestra cómo una factura se convierte en una matrícula activa y, eventualmente, en un certificado entregado por email.
flowchart LR
subgraph FS["FacturaScripts"]
direction TB
FC[FacturaCliente<br/>pagada=true]
PC[PresupuestoCliente<br/>PedidoCliente]
CT[Contacto]
PR[Producto<br/>moodle_course=true]
end
subgraph WQ["WorkQueue (async workers)"]
direction TB
EW[EnrolmentWorker]
PW[PreEnrolmentWorker]
CSW[ContactSyncWorker]
CDW[ContactDeleteWorker]
OW[OnboardingWorker]
BSW[BadgeSyncWorker]
end
subgraph PLUG["Plugin models"]
direction TB
UM[MoodleUserMap]
CM[MoodleCourseMap]
EN[MoodleEnrolment]
CE[MoodleCertificate]
end
subgraph MOODLE["Moodle LMS (REST WS)"]
direction TB
MU[core_user_*]
ME[enrol_manual_*]
MB[core_badges_*]
MM[core_message_*]
end
subgraph OUT["Output"]
direction TB
PDF[PDF<br/>CertificatePdfGenerator]
EMAIL[Email<br/>NewMail + ExpiryNotifier]
end
FC -- "Model.FacturaCliente.Update" --> EW
PC -- "Model.Presupuesto/Pedido.Update" --> PW
CT -- "Model.Contacto.Update" --> CSW
CT -- "Model.Contacto.Delete" --> CDW
UM -. "Model.MoodleUserMap.Insert" .-> OW
UM -. "Model.MoodleUserMap.Save (cascade-risk, F6.1)" .-> BSW
EW --> EN
PW --> EN
CSW --> MU
CDW --> MU
OW --> ME
OW --> MM
BSW --> MB
EN --> ME
UM <--> MU
CM <--> MU
PR --> CM
EN --> CE
CE --> PDF
CE --> EMAIL
classDef fs fill:#d0e6ff,stroke:#0060b0,color:#000;
classDef wq fill:#fff4c2,stroke:#b08000,color:#000;
classDef plug fill:#d4edda,stroke:#0c6b2a,color:#000;
classDef moodle fill:#f8d7da,stroke:#a02030,color:#000;
classDef out fill:#e7d4f5,stroke:#5a2a8a,color:#000;
class FC,PC,CT,PR fs
class EW,PW,CSW,CDW,OW,BSW wq
class UM,CM,EN,CE plug
class MU,ME,MB,MM moodle
class PDF,EMAIL out
Leyenda rápida:
- Flechas sólidas: evento
Model.X.Update/Insert/Deleteque dispara el worker correspondiente. - Flechas punteadas: eventos en vigilancia activa para la Fase 6 (cascadas pendientes de cortar).
- Los cron jobs (
healthCheck,userSync,courseSync,reconciliation,cleanup,expiryCheck) consumen los mismos modelos pero se ejecutan en horario propio — no aparecen en este diagrama para mantenerlo legible.
@since 2.0 — V2.0-ACTION-PLAN F11.4 · §9.4El siguiente diagrama complementa el flujo principal con las piezas introducidas durante la auditoría v2.0: capa de seguridad, endpoint de webhooks, papelera, registros de auditoría y sincronía de progreso académico. Se mantiene en un diagrama aparte para no saturar el canvas principal.
flowchart TB
subgraph EDGE["Capa de entrada"]
direction TB
HTTP[Request HTTP]
WH[POST /ApiMoodleWebhook]
PDF[GET /MoodleCertificatePdf]
end
subgraph SEC["Security primitives"]
direction TB
RL[RateLimiter<br/>F2.10]
CSRF[Signed URL<br/>F2.9 HMAC-SHA256]
IPV[IpValidator<br/>F7.1 SSRF guard]
TC[TokenCipher<br/>F5.12 AES-256-GCM]
HSAN[HtmlSanitizer<br/>F2.1]
CSP[CspHeader<br/>F2.11]
end
subgraph WHOOK["Webhook pipeline F10.1"]
direction TB
WV[WebhookVerifier]
WD[WebhookDispatcher]
WL[(moodle_webhook_log)]
subgraph HND["Handlers"]
direction TB
H1[EnrolmentCreated]
H2[EnrolmentDeleted]
H3[CourseCompleted]
H4[UserUpdated]
end
end
subgraph JOBS["Cron jobs (every 6h / 1d)"]
direction TB
PS[progressSync<br/>F10.2]
ES[expiryCheck<br/>F6.10]
REC[reconciliation]
CLE[cleanup + papelera]
end
subgraph AUDIT["Observability"]
direction TB
AL[(moodle_audit_log)]
BL[BufferedLogger<br/>F10.10]
PM[PiiMasker<br/>F8.5]
end
subgraph DATA["Plugin data"]
direction TB
MI[(moodle_instances<br/>+ webhook_secret<br/>+ username_strategy)]
EN2[(moodle_enrolments<br/>+ progress_percent<br/>+ deleted_at)]
end
HTTP --> RL
HTTP --> CSRF
WH --> WV
PDF --> CSRF
WV --> TC
WV --> WL
WV --> WD
WD --> H1 & H2 & H3 & H4
H1 & H2 & H3 & H4 --> EN2
MI -. "AES-256-GCM at rest" .-> TC
PS --> EN2
ES --> EN2
REC --> EN2
CLE --> EN2
WV --> AL
CSRF --> AL
RL --> AL
PS --> BL
BL --> AL
AL -. "pii-masked" .-> PM
classDef edge fill:#d9e8ff,stroke:#002b70,color:#000;
classDef sec fill:#ffe9c2,stroke:#a25100,color:#000;
classDef hook fill:#d4edda,stroke:#0c6b2a,color:#000;
classDef job fill:#fff4c2,stroke:#b08000,color:#000;
classDef audit fill:#f8d7da,stroke:#a02030,color:#000;
classDef data fill:#e7d4f5,stroke:#5a2a8a,color:#000;
class HTTP,WH,PDF edge
class RL,CSRF,IPV,TC,HSAN,CSP sec
class WV,WD,WL,H1,H2,H3,H4 hook
class PS,ES,REC,CLE job
class AL,BL,PM audit
class MI,EN2 data
Notas:
- La capa Security primitives agrupa los helpers de
Lib/Security/*introducidos en las Fases 2, 5 y 7. Cualquier controlador expuesto al exterior pasa por al menos uno de ellos. - WebhookDispatcher mantiene la separación "verificar → auditar →
despachar". El registro
moodle_webhook_logse escribe tanto en éxito como en rechazo, facilitando el triage desdeListMoodleAuditLog(F10.3). - BufferedLogger (F10.10) acumula eventos de los cron loops y los vuelca agrupados, reduciendo I/O de log en fase de alta actividad.
- Conexión a múltiples instancias de Moodle simultáneamente
- Test de conexión y monitoreo de estado (activa, mantenimiento, inactiva)
- Visualización de información del sitio (versión, release, funciones WS disponibles)
- Soporte para entornos: producción, staging, desarrollo
- Importación masiva de usuarios desde Moodle a FacturaScripts
- Mapeo bidireccional usuario Moodle ↔ contacto FacturaScripts
- Creación automática de clientes/contactos al importar
- Sincronización individual y masiva
- Importación y sincronización de cursos desde Moodle
- Vinculación de cursos Moodle con productos de FacturaScripts
- Creación automática de productos y familias por curso
- Duplicación de cursos directamente desde FS
- Gestión de categorías de cursos (importar, crear, sincronizar)
- Sincronización de imágenes de portada entre producto y curso
- Visualización en tiempo real del contenido del curso vía API
- Gestión de secciones: crear, ocultar/mostrar, mover, eliminar
- Gestión de actividades: ocultar/mostrar, duplicar, mover entre secciones, eliminar
- Modo stealth (solo enlace) para actividades
- Indentación de actividades (derecha/izquierda)
- Cambio de modo de grupo (sin grupos, grupos separados, grupos visibles)
- Acciones masivas con selección múltiple
- Modal de detalle de módulo con información completa
- Gestión de matrículas por curso e instancia
- Soporte para métodos: manual, auto-matrícula, pago, cohort, meta-enlace
- Estados de matrícula: pendiente, matriculado, suspendido, desmatriculado
- Vinculación con documentos comerciales (facturas, pedidos, presupuestos)
- Meta-matrículas entre cursos
- Importación de cohorts desde Moodle
- Sincronización de miembros
- Gestión de membresía (agregar/eliminar miembros)
- Mapeo de los 8 roles estándar de Moodle por instancia
- Importación automática de roles estándar
- Sincronización de badges de Moodle a FacturaScripts por usuario
- Sincronización masiva de badges de todos los usuarios mapeados
- Sincronización automática al guardar un mapeo de usuario (Worker)
- Listado global de badges con filtros por contacto e instancia
- Vista de detalle de badge con datos de Moodle (nombre, curso, fecha, hash, URLs)
- Visualización de grupos de un curso en tiempo real desde Moodle
- Crear y eliminar grupos en un curso directamente desde FS
- Ver miembros de cada grupo con conteo
- Agregar y eliminar miembros de grupos
- Chat bidireccional estilo WhatsApp con usuarios Moodle (pestaña "Chat" en mapeo de usuario)
- Auto-refresh cada 5 segundos — los mensajes nuevos aparecen automáticamente sin recargar la página
- Nombre del contacto de FS en las burbujas de chat (no el ID de Moodle)
- Historial de conversación en tiempo real via API de Moodle
- Envío de mensajes instantáneos — el usuario los recibe en su mensajería de Moodle
- Respuestas del usuario visibles automáticamente en FS
- Botón "Enviar Mensaje" rápido desde el formulario del usuario (modal)
- Envío masivo a todos los matriculados de un curso (pestaña "Mensajería" en el curso)
- Selección de destinatarios: todos los matriculados o usuarios específicos
- Hub de Conversaciones: página central con todas las conversaciones abiertas de todas las instancias
- Semáforo visual: rojo = mensajes sin leer, verde = todo leído
- Badge con número de mensajes no leídos por conversación
- Vista previa del último mensaje y marca temporal
- Filtros: Todos, Solo No Leídos, Solo Leídos
- Enlace directo al chat de cada usuario
- Ordenación: conversaciones no leídas primero, luego por fecha del último mensaje
- Botón "Nueva Conversación" con buscador de usuarios mapeados sin conversación abierta
- Auto-refresh cada 10 segundos sin recargar la página
- Marcado automático de mensajes como leídos al abrir un chat
- Icono de chat en la barra de navegación con badge de mensajes no leídos (se actualiza cada 30 segundos)
- Progreso académico del alumno (cursos, actividades completadas, calificaciones) en tiempo real vía API
- Matrículas sin facturar (enrolled sin factura vinculada)
- Matrículas por estado (pendiente, matriculado, suspendido, desmatriculado)
- Matrículas por curso con filtros financieros
- Matrícula automática: al pagar una factura con productos vinculados a cursos, el alumno se matricula automáticamente en Moodle
- Pre-matrícula: al crear presupuestos o pedidos, se generan matrículas pendientes que se activan al facturar
- Sincronización de contactos: al modificar un contacto en FS, los datos se sincronizan automáticamente con Moodle
- Suspensión automática: al eliminar un contacto en FS, se suspende su cuenta y matrículas en Moodle
- Health check (cada hora): monitoreo automático del estado de todas las instancias Moodle
- Sincronización incremental (cada 6 horas): sincronización de usuarios y cursos con resolución de conflictos
- Reconciliación (diaria): verificación de integridad de mapeos de usuarios y matrículas contra Moodle
- Limpieza (diaria): eliminación automática de mapeos huérfanos (contactos eliminados)
- Control de expiración (cada 6 horas): detección de matrículas por vencer (7 días), expiración automática y generación de presupuestos de renovación
- Crear, leer y eliminar notas en el perfil de usuarios de Moodle desde FS
- Pestaña "Notas" en el mapeo de usuario con historial completo
- Soporte para notas de tipo sitio y personal
- Notas ordenadas por fecha de creación (más reciente primero)
- Crear y eliminar eventos en el calendario de usuarios de Moodle desde FS
- Pestaña "Calendario" en el mapeo de usuario
- Visualización de eventos existentes con tipo y descripción
- Soporte para eventos de tipo usuario
- Campo
duracion_diasen cursos para definir la duración de acceso tras la matrícula - Cálculo automático de
timeendal matricular (timestart + duración en días) - Generación automática de presupuestos de renovación cuando una matrícula está por expirar (7 días)
- El presupuesto incluye el producto del curso al precio configurado, vinculado al cliente del contacto
- Flujo completo: presupuesto → aprobación → factura → EnrolmentWorker renueva la matrícula
- Configuración por instancia: curso de bienvenida, cohort por defecto, mensaje de bienvenida
- Al crear un nuevo mapeo de usuario, el sistema automáticamente:
- Matricula al usuario en el curso de bienvenida configurado
- Lo asigna al cohort por defecto
- Le envía un mensaje de bienvenida personalizado (variables: %name%, %username%, %site%)
- Crea una nota de onboarding en su perfil de Moodle
- Activación/desactivación por instancia con checkbox
- FacturaScripts >= 2025.6
- Moodle >= 4.1 LTS (soportadas hasta 5.x; 4.0 marcado automáticamente como
unsupported) - PHP >= 8.0 con extensión cURL
- MySQL 5.7+ / MariaDB 10.4+ / PostgreSQL 13+
@since 2.0 — V2.0-ACTION-PLAN F11.6 · §9.7Esta tabla es el contrato de soporte del plugin. Ver
docs/SUPPORTED-VERSIONS.mdpara el detalle por componente.
| Dimensión | Soportado | No soportado |
|---|---|---|
| FacturaScripts | 2025.6 → 2025.latest | < 2025.6 (bloqueado por facturascripts.ini::min_version) |
| PHP | 8.0, 8.1, 8.2 (CI matrix); 8.3 best-effort | < 8.0 |
| Moodle | 4.1 LTS + (MoodleClient::MIN_MOODLE_RELEASE = '4.1') |
4.0 marcado unsupported · < 4.0 bloqueado |
| MySQL / MariaDB | MySQL 5.7+, MariaDB 10.4+ | MySQL 5.6, MariaDB < 10.4 |
| PostgreSQL | 13+ | < 13 |
| Navegadores | Chrome/Edge últimos 2, Firefox últimos 2, Safari 16+ | IE 11, Safari < 16 |
| cURL | >= 7.50 (HTTP/2 + TLS moderno) | < 7.50 |
Combinaciones probadas por CI (.github/workflows/ci.yml):
- PHP 8.0 + FS 2025.6 + MySQL 8.0
- PHP 8.1 + FS 2025.81 + MySQL 8.0
- PHP 8.2 + FS 2025.81 + MySQL 8.0 (también genera reporte de cobertura)
- Copie la carpeta
MoodleManagementen el directorioPluginsde FacturaScripts - Active el plugin desde Admin > Plugins
- Configure al menos una instancia Moodle desde Gestión Moodle > Instancias Moodle
Para que el plugin funcione correctamente, debe crear un servicio web en Moodle con las funciones necesarias y generar un token de acceso.
- Vaya a Administración del sitio > General > Funciones avanzadas
- Marque Habilitar servicios web (
enablewebservices) - Guarde los cambios
- Vaya a Administración del sitio > Servidor > Servicios web > Gestionar protocolos
- Habilite el protocolo REST
- Vaya a Administración del sitio > Usuarios > Cuentas > Agregar un nuevo usuario
- Cree un usuario dedicado (ej:
ws_facturascripts) - Asigne el rol Manager a nivel de sistema:
- Administración del sitio > Usuarios > Permisos > Asignar roles globales
- Seleccione Manager y agregue el usuario creado
- Vaya a Administración del sitio > Servidor > Servicios web > Servicios externos
- Haga clic en Agregar
- Configure:
- Nombre:
FacturaScripts Integration - Nombre corto:
facturascripts - Habilitado: Sí
- Usuarios autorizados: Sí (solo usuarios específicos)
- Nombre:
- Guarde
- En la lista de servicios, haga clic en Usuarios autorizados y agregue el usuario de servicio creado en el Paso 3
- En la lista de servicios, haga clic en Funciones junto al servicio
FacturaScripts Integration - Agregue las siguientes funciones:
| Función | Descripción |
|---|---|
core_webservice_get_site_info |
Test de conexión e información del sitio |
| Función | Descripción |
|---|---|
core_user_get_users |
Buscar usuarios |
core_user_get_users_by_field |
Obtener usuario por campo |
core_user_create_users |
Crear usuarios |
core_user_update_users |
Actualizar usuarios |
core_user_delete_users |
Eliminar usuarios |
| Función | Descripción |
|---|---|
core_cohort_get_cohorts |
Obtener cohorts |
core_cohort_search_cohorts |
Buscar cohorts |
core_cohort_create_cohorts |
Crear cohorts |
core_cohort_update_cohorts |
Actualizar cohorts |
core_cohort_delete_cohorts |
Eliminar cohorts |
core_cohort_add_cohort_members |
Agregar miembros a cohort |
core_cohort_delete_cohort_members |
Eliminar miembros de cohort |
core_cohort_get_cohort_members |
Obtener miembros de cohort |
| Función | Descripción |
|---|---|
core_course_get_courses |
Obtener cursos |
core_course_get_courses_by_field |
Obtener curso por campo |
core_course_search_courses |
Buscar cursos |
core_course_create_courses |
Crear cursos |
core_course_update_courses |
Actualizar cursos |
core_course_delete_courses |
Eliminar cursos |
core_course_duplicate_course |
Duplicar curso |
core_course_get_contents |
Obtener contenido del curso |
core_course_get_categories |
Obtener categorías |
core_course_create_categories |
Crear categorías |
core_course_update_categories |
Actualizar categorías |
core_course_delete_categories |
Eliminar categorías |
| Función | Descripción |
|---|---|
core_course_get_course_module |
Detalle de un módulo por cmid |
core_course_get_course_module_by_instance |
Detalle de módulo por tipo+instancia |
core_course_get_course_content_items |
Tipos de actividad disponibles |
core_courseformat_update_course |
Acciones del editor de curso (mostrar/ocultar/mover/duplicar/eliminar módulos y secciones, indentación, modo de grupo) |
core_course_delete_modules |
Eliminar módulos |
| Función | Descripción |
|---|---|
enrol_manual_enrol_users |
Matricular usuarios manualmente |
enrol_manual_unenrol_users |
Desmatricular usuarios |
core_enrol_get_enrolled_users |
Obtener matriculados en un curso |
core_enrol_get_users_courses |
Obtener cursos de un usuario |
core_enrol_get_course_enrolment_methods |
Métodos de matrícula de un curso |
core_enrol_get_potential_users |
Usuarios potenciales para matricular |
core_enrol_search_users |
Buscar usuarios para matrícula |
enrol_self_enrol_user |
Auto-matrícula |
enrol_self_get_instance_info |
Info de auto-matrícula |
enrol_meta_add_instances |
Agregar meta-matrículas |
enrol_meta_delete_instances |
Eliminar meta-matrículas |
| Función | Descripción |
|---|---|
core_completion_get_activities_completion_status |
Estado de completion por actividad |
core_completion_get_course_completion_status |
Estado de completion del curso |
gradereport_user_get_grade_items |
Calificaciones del usuario por curso |
| Función | Descripción |
|---|---|
core_badges_get_user_badges |
Obtener badges de un usuario |
| Función | Descripción |
|---|---|
core_group_get_course_groups |
Listar grupos de un curso |
core_group_create_groups |
Crear grupos |
core_group_update_groups |
Actualizar grupos |
core_group_delete_groups |
Eliminar grupos |
core_group_get_group_members |
Obtener miembros de un grupo |
core_group_add_group_members |
Agregar miembros a grupo |
core_group_delete_group_members |
Eliminar miembros de grupo |
| Función | Descripción |
|---|---|
core_message_send_instant_messages |
Enviar mensajes instantáneos a usuarios |
core_message_get_conversation_between_users |
Obtener conversación entre dos usuarios |
core_message_get_conversation_messages |
Obtener mensajes de una conversación |
core_message_send_messages_to_conversation |
Enviar mensaje a una conversación existente |
core_message_get_conversations |
Listar conversaciones del usuario (hub de conversaciones) |
core_message_get_unread_conversations_count |
Contar conversaciones con mensajes no leídos (badge navbar) |
core_message_mark_all_conversation_messages_as_read |
Marcar todos los mensajes de una conversación como leídos |
| Función | Descripción |
|---|---|
core_notes_create_notes |
Crear notas en perfil de usuario |
core_notes_get_course_notes |
Obtener notas de un curso/usuario |
core_notes_delete_notes |
Eliminar notas |
| Función | Descripción |
|---|---|
core_calendar_get_calendar_events |
Obtener eventos del calendario |
core_calendar_create_calendar_events |
Crear eventos en el calendario |
core_calendar_delete_calendar_events |
Eliminar eventos del calendario |
| Función | Descripción |
|---|---|
core_role_assign_roles |
Asignar roles |
core_role_unassign_roles |
Desasignar roles |
- Vaya a Administración del sitio > Servidor > Servicios web > Gestionar tokens
- Haga clic en Crear token
- Seleccione el usuario de servicio (ej:
ws_facturascripts) - Seleccione el servicio:
FacturaScripts Integration - Guarde y copie el token generado
- En FacturaScripts, vaya a Gestión Moodle > Instancias Moodle
- Haga clic en + Nuevo
- Complete:
- Nombre del sitio: Nombre descriptivo
- URL: URL completa de su Moodle (ej:
https://miacademia.com/moodle) - Token: Pegue el token generado en el Paso 6
- Guarde y haga clic en Probar Conexión para verificar
El sistema de mensajería permite comunicación bidireccional entre FacturaScripts y los usuarios de Moodle. Los mensajes se envían y reciben a través del usuario de servicio WS (actúa como "soporte").
-
Funciones WS registradas: Asegúrese de que las 7 funciones de mensajería estén agregadas al servicio WS en Moodle (ver Paso 5 - Mensajería):
core_message_send_instant_messagescore_message_get_conversation_between_userscore_message_get_conversation_messagescore_message_send_messages_to_conversationcore_message_get_conversations(hub de conversaciones)core_message_get_unread_conversations_count(badge del navbar)core_message_mark_all_conversation_messages_as_read(marcado como leídos)
-
Mensajería habilitada en Moodle: Verifique que la mensajería esté activa en Administración del sitio > General > Funciones avanzadas > Habilitar mensajería (
messaging). -
Permisos del usuario WS: El usuario de servicio debe tener los capabilities:
moodle/site:sendmessage— enviar mensajesmoodle/site:readallmessages— leer conversaciones (normalmente incluido en el rol Manager)
- Vaya a Gestión Moodle > Instancias Moodle y edite su instancia
- Haga clic en Probar Conexión — esto obtiene y almacena automáticamente el
service_userid(ID del usuario WS en Moodle), necesario para identificar al remitente en el chat - Verifique que aparezca el campo Service User ID con un valor numérico en el formulario de la instancia
- Vaya a Gestión Moodle > Usuarios Moodle y abra un mapeo de usuario
- Haga clic en la pestaña Chat
- Si no existe conversación previa, verá el chat vacío listo para enviar el primer mensaje — la conversación se crea automáticamente en Moodle al enviar
- Escriba su mensaje y presione Enter o el botón de enviar
- Los mensajes enviados aparecen como burbujas verdes (estilo WhatsApp); las respuestas del usuario en burbujas blancas con el nombre del contacto de FS
- El chat se actualiza automáticamente cada 5 segundos — no es necesario recargar la página para ver nuevos mensajes
Nota: También puede enviar un mensaje rápido desde el botón Enviar Mensaje en la pestaña principal del usuario (abre un modal).
- Vaya a Gestión Moodle > Cursos Moodle y abra un curso
- Haga clic en la pestaña Mensajería
- Seleccione el modo de destinatarios:
- Todos los matriculados: envía a todos los usuarios matriculados activos del curso
- Usuarios seleccionados: permite elegir destinatarios específicos de la lista
- Escriba el mensaje y haga clic en Enviar Mensaje
- Haga clic en el icono de chat en la barra de navegación superior (muestra un badge rojo con el número de mensajes no leídos)
- Verá la lista de todas las conversaciones abiertas de todas las instancias Moodle activas
- Las conversaciones con mensajes sin leer aparecen primero, marcadas con un semáforo rojo y un badge con el conteo
- Use los botones de filtro: Todos, Solo No Leídos o Solo Leídos para filtrar la lista
- Haga clic en cualquier conversación para ir directamente al chat del usuario — los mensajes se marcan automáticamente como leídos
- Use Nueva Conversación para iniciar un chat con un usuario mapeado que aún no tenga conversación abierta
- La lista de conversaciones se actualiza automáticamente cada 10 segundos
- El remitente es siempre el usuario de servicio WS — no se puede enviar como otro usuario
- Solo se leen conversaciones donde participa el usuario WS (no hay acceso a conversaciones de terceros)
- El auto-refresh del chat consulta la API de Moodle cada 5 segundos; se pausa automáticamente cuando la pestaña del navegador no está visible
- El badge de la barra de navegación se actualiza cada 30 segundos
@since 2.0 — V2.0-ACTION-PLAN F11.1 · §9.1
| Ámbito | Limitación | Seguimiento |
|---|---|---|
| Webhooks | El receptor espera payloads en el formato interno definido por el plugin (ver docs/EVENTS.md). Moodle no emite webhooks por defecto; se requiere un mediador (Event Observer + curl). |
v2.1 — cliente de referencia en PHP incluido en docs. |
| Papelera | La papelera (F10.4) permite restaurar o purgar, pero la eliminación desde las vistas principales sigue siendo física. Para soft-delete masivo, marcar deleted_at desde SQL o vía worker. |
v2.1 — hook execBeforeDelete en modelos. |
| Dashboard | El dashboard cachea el payload durante 60 s (F10.9). Tras una sincronización masiva, usar ?refresh=1 para forzar una lectura fresca. |
Documentado en-place. |
| Username alias | El modo random_alias solo aplica al crear cuentas nuevas. Los usuarios ya mapeados con nombre derivado conservan su username (para cambiarlo se debe des-enrolar, renombrar en Moodle y re-mapear). |
v2.1 — asistente de renombrado. |
| Localización | Las traducciones cubren ES variantes + EN + FR + PT (PT/BR) + IT + DE + CA + GL + EU + CA-VL + PL + CS. El resto hace fallback a inglés. | Open PR — idiomas adicionales vía pull request. |
| Navegadores | Chart.js 4.x (F3.1) requiere Chrome/Edge últimos 2, Firefox últimos 2, Safari 16+. IE11 no soportado. | Constraint formalizado en docs/SUPPORTED-VERSIONS.md. |
| Moodle mínimo | Moodle 4.1 LTS. Instancias 4.0 marcadas status=unsupported automáticamente; versiones < 4.0 bloqueadas (ver MoodleClient::MIN_MOODLE_RELEASE). |
Política estable. |
| MoodleClient | Clase god (~1600 LOC) con superficie legacy. Fase 8 creó facades namespaced (Lib/Moodle/Api/*) pero la migración de llamadores es gradual. |
v2.2 — deprecación de llamadas directas tras periodo 6 meses. |
| Certificados | El generador PDF usa Cezpdf (dependencia de FS core) con plantillas ROT50/Template simples. Plantillas HTML/CSS full están en el backlog. | v2.1 — renderer Twig → wkhtmltopdf. |
| Concurrencia | Los locks cooperativos (Lib/Cron/Lock) usan GET_LOCK/pg_try_advisory_lock. Si el motor es SQLite (solo tests), los locks son no-ops. |
By design — SQLite es solo para tests. |
Ver también: docs/TROUBLESHOOTING.md, docs/UPGRADE.md, docs/SUPPORTED-VERSIONS.md.
Español (ES, AR, CL, CO, CR, DO, EC, GT, MX, PA, PE, UY), Inglés, Francés, Portugués (PT, BR), Italiano, Alemán, Catalán, Gallego, Euskera, Valenciano, Polaco y Checo.
Si necesita una integración personalizada con su plataforma LMS o funcionalidades adicionales para su organización, no dude en contactarnos:
- Email: dfelipe.monroyc@gmail.com
- Web: diegomonroydev.com
LGPL v3 - GNU Lesser General Public License
FacturaScripts plugin for managing Moodle platforms directly from your ERP. Connect your billing system with your LMS through the Moodle REST API.
The diagram shows how a paid invoice becomes an active enrolment and eventually a certificate delivered by email.
flowchart LR
subgraph FS["FacturaScripts"]
direction TB
FC[FacturaCliente<br/>pagada=true]
PC[PresupuestoCliente<br/>PedidoCliente]
CT[Contacto]
PR[Producto<br/>moodle_course=true]
end
subgraph WQ["WorkQueue (async workers)"]
direction TB
EW[EnrolmentWorker]
PW[PreEnrolmentWorker]
CSW[ContactSyncWorker]
CDW[ContactDeleteWorker]
OW[OnboardingWorker]
BSW[BadgeSyncWorker]
end
subgraph PLUG["Plugin models"]
direction TB
UM[MoodleUserMap]
CM[MoodleCourseMap]
EN[MoodleEnrolment]
CE[MoodleCertificate]
end
subgraph MOODLE["Moodle LMS (REST WS)"]
direction TB
MU[core_user_*]
ME[enrol_manual_*]
MB[core_badges_*]
MM[core_message_*]
end
subgraph OUT["Output"]
direction TB
PDF[PDF<br/>CertificatePdfGenerator]
EMAIL[Email<br/>NewMail + ExpiryNotifier]
end
FC -- "Model.FacturaCliente.Update" --> EW
PC -- "Model.Presupuesto/Pedido.Update" --> PW
CT -- "Model.Contacto.Update" --> CSW
CT -- "Model.Contacto.Delete" --> CDW
UM -. "Model.MoodleUserMap.Insert" .-> OW
UM -. "Model.MoodleUserMap.Save (cascade-risk, F6.1)" .-> BSW
EW --> EN
PW --> EN
CSW --> MU
CDW --> MU
OW --> ME
OW --> MM
BSW --> MB
EN --> ME
UM <--> MU
CM <--> MU
PR --> CM
EN --> CE
CE --> PDF
CE --> EMAIL
classDef fs fill:#d0e6ff,stroke:#0060b0,color:#000;
classDef wq fill:#fff4c2,stroke:#b08000,color:#000;
classDef plug fill:#d4edda,stroke:#0c6b2a,color:#000;
classDef moodle fill:#f8d7da,stroke:#a02030,color:#000;
classDef out fill:#e7d4f5,stroke:#5a2a8a,color:#000;
class FC,PC,CT,PR fs
class EW,PW,CSW,CDW,OW,BSW wq
class UM,CM,EN,CE plug
class MU,ME,MB,MM moodle
class PDF,EMAIL out
Quick legend:
- Solid arrows:
Model.X.Update/Insert/Deleteevent that fires the corresponding worker. - Dotted arrows: events tracked for active remediation in Phase 6 (cascades to be cut).
- Cron jobs (
healthCheck,userSync,courseSync,reconciliation,cleanup,expiryCheck) consume the same models but run on their own schedule — omitted here to keep the diagram readable.
@since 2.0 — V2.0-ACTION-PLAN F11.4 · §9.4The diagram below complements the main flow with the components introduced during the v2.0 audit: the security layer, the webhook endpoint, the trash viewer, audit logs, and the academic progress sync. Kept separate to avoid overloading the main canvas.
flowchart TB
subgraph EDGE["Inbound layer"]
direction TB
HTTP[HTTP request]
WH[POST /ApiMoodleWebhook]
PDF[GET /MoodleCertificatePdf]
end
subgraph SEC["Security primitives"]
direction TB
RL[RateLimiter<br/>F2.10]
CSRF[Signed URL<br/>F2.9 HMAC-SHA256]
IPV[IpValidator<br/>F7.1 SSRF guard]
TC[TokenCipher<br/>F5.12 AES-256-GCM]
HSAN[HtmlSanitizer<br/>F2.1]
CSP[CspHeader<br/>F2.11]
end
subgraph WHOOK["Webhook pipeline F10.1"]
direction TB
WV[WebhookVerifier]
WD[WebhookDispatcher]
WL[(moodle_webhook_log)]
subgraph HND["Handlers"]
direction TB
H1[EnrolmentCreated]
H2[EnrolmentDeleted]
H3[CourseCompleted]
H4[UserUpdated]
end
end
subgraph JOBS["Cron jobs (6h / daily)"]
direction TB
PS[progressSync<br/>F10.2]
ES[expiryCheck<br/>F6.10]
REC[reconciliation]
CLE[cleanup + trash]
end
subgraph AUDIT["Observability"]
direction TB
AL[(moodle_audit_log)]
BL[BufferedLogger<br/>F10.10]
PM[PiiMasker<br/>F8.5]
end
subgraph DATA["Plugin data"]
direction TB
MI[(moodle_instances<br/>+ webhook_secret<br/>+ username_strategy)]
EN2[(moodle_enrolments<br/>+ progress_percent<br/>+ deleted_at)]
end
HTTP --> RL
HTTP --> CSRF
WH --> WV
PDF --> CSRF
WV --> TC
WV --> WL
WV --> WD
WD --> H1 & H2 & H3 & H4
H1 & H2 & H3 & H4 --> EN2
MI -. "AES-256-GCM at rest" .-> TC
PS --> EN2
ES --> EN2
REC --> EN2
CLE --> EN2
WV --> AL
CSRF --> AL
RL --> AL
PS --> BL
BL --> AL
AL -. "pii-masked" .-> PM
classDef edge fill:#d9e8ff,stroke:#002b70,color:#000;
classDef sec fill:#ffe9c2,stroke:#a25100,color:#000;
classDef hook fill:#d4edda,stroke:#0c6b2a,color:#000;
classDef job fill:#fff4c2,stroke:#b08000,color:#000;
classDef audit fill:#f8d7da,stroke:#a02030,color:#000;
classDef data fill:#e7d4f5,stroke:#5a2a8a,color:#000;
class HTTP,WH,PDF edge
class RL,CSRF,IPV,TC,HSAN,CSP sec
class WV,WD,WL,H1,H2,H3,H4 hook
class PS,ES,REC,CLE job
class AL,BL,PM audit
class MI,EN2 data
Notes:
- The Security primitives group gathers the helpers under
Lib/Security/*introduced in Phases 2, 5, and 7. Any externally-exposed controller runs through at least one of them. - WebhookDispatcher keeps the "verify → audit → dispatch"
separation.
moodle_webhook_logcaptures every request (accepted or rejected) for triage viaListMoodleAuditLog(F10.3). - BufferedLogger (F10.10) batches cron loop events and flushes them in bulk, reducing log I/O during high-activity windows.
- Connect to multiple Moodle instances simultaneously
- Connection testing and status monitoring (active, maintenance, inactive)
- Site information display (version, release, available WS functions)
- Environment support: production, staging, development
- Bulk user import from Moodle to FacturaScripts
- Bidirectional mapping Moodle user ↔ FacturaScripts contact
- Automatic client/contact creation on import
- Individual and bulk synchronization
- Course import and synchronization from Moodle
- Link Moodle courses with FacturaScripts products
- Automatic product and family creation per course
- Course duplication directly from FS
- Course category management (import, create, sync)
- Cover image synchronization between product and course
- Real-time course content display via API
- Section management: create, show/hide, move, delete
- Activity management: show/hide, duplicate, move between sections, delete
- Stealth mode (link only) for activities
- Activity indentation (right/left)
- Group mode switching (no groups, separate groups, visible groups)
- Bulk actions with multiple selection
- Module detail modal with full information
- Enrolment management by course and instance
- Method support: manual, self-enrolment, payment, cohort, meta-link
- Enrolment statuses: pending, enrolled, suspended, unenrolled
- Link to commercial documents (invoices, orders, estimates)
- Meta-enrolments between courses
- Cohort import from Moodle
- Member synchronization
- Membership management (add/remove members)
- Mapping of the 8 standard Moodle roles per instance
- Automatic standard role import
- Sync Moodle badges to FacturaScripts per user
- Bulk badge sync for all mapped users
- Automatic sync when saving a user mapping (Worker)
- Global badge listing with filters by contact and instance
- Badge detail view with Moodle data (name, course, date, hash, URLs)
- Real-time course group display from Moodle
- Create and delete groups in a course directly from FS
- View group members with count
- Add and remove group members
- WhatsApp-style bidirectional chat with Moodle users ("Chat" tab in user mapping)
- Auto-refresh every 5 seconds — new messages appear automatically without page reload
- FS contact name displayed in chat bubbles (not the Moodle ID)
- Real-time conversation history via Moodle API
- Send instant messages — the user receives them in their Moodle messaging
- User replies appear automatically in FS
- Quick "Send Message" button from user form (modal)
- Bulk messaging to all enrolled users in a course ("Messaging" tab in course view)
- Recipient selection: all enrolled or specific users
- Conversations Hub: central page showing all open conversations across all instances
- Visual semaphore: red = unread messages, green = all read
- Badge with unread message count per conversation
- Last message preview and timestamp
- Filters: All, Unread Only, Read Only
- Direct link to each user's chat
- Sorting: unread conversations first, then by last message time
- "New Conversation" button with search for mapped users without an open conversation
- Auto-refresh every 10 seconds without page reload
- Automatic mark-as-read when opening a chat
- Navbar chat icon with unread message badge (refreshes every 30 seconds)
- Real-time student academic progress (courses, completed activities, grades) via API
- Unbilled enrolments (enrolled without linked invoice)
- Enrolments by status (pending, enrolled, suspended, unenrolled)
- Enrolments by course with financial filters
- Automatic enrolment: when an invoice with course-linked products is paid, the student is automatically enrolled in Moodle
- Pre-enrolment: when creating quotes or orders, pending enrolments are generated and activated upon invoicing
- Contact synchronization: when a contact is modified in FS, data is automatically synced to Moodle
- Automatic suspension: when a contact is deleted in FS, their Moodle account and enrolments are suspended
- Health check (hourly): automatic monitoring of all Moodle instance statuses
- Incremental sync (every 6 hours): user and course synchronization with conflict resolution
- Reconciliation (daily): integrity verification of user and enrolment mappings against Moodle
- Cleanup (daily): automatic removal of orphaned mappings (deleted contacts)
- Expiry control (every 6 hours): detection of expiring enrolments (7 days), automatic expiration and renewal estimate generation
- Create, read and delete notes on Moodle user profiles from FS
- "Notes" tab in user mapping with full history
- Support for site and personal note types
- Notes sorted by creation date (newest first)
- Create and delete events on Moodle user calendars from FS
- "Calendar" tab in user mapping
- Display existing events with type and description
- Support for user-type events
duracion_diasfield on courses to define access duration after enrolment- Automatic
timeendcalculation on enrolment (timestart + duration in days) - Automatic renewal estimate generation when an enrolment is about to expire (7 days)
- Estimate includes the course product at the configured price, linked to the contact's client
- Full flow: estimate → approval → invoice → EnrolmentWorker renews the enrolment
- Per-instance configuration: welcome course, default cohort, welcome message
- When creating a new user mapping, the system automatically:
- Enrols the user in the configured welcome course
- Assigns them to the default cohort
- Sends a personalized welcome message (variables: %name%, %username%, %site%)
- Creates an onboarding note on their Moodle profile
- Enable/disable per instance with checkbox
- FacturaScripts >= 2025.6
- Moodle >= 4.1 LTS (4.0 is automatically flagged as
unsupported, supported through 5.x) - PHP >= 8.0 with cURL extension
- MySQL 5.7+ / MariaDB 10.4+ / PostgreSQL 13+
@since 2.0 — V2.0-ACTION-PLAN F11.6 · §9.7This table is the plugin's support contract. See
docs/SUPPORTED-VERSIONS.mdfor component-level detail.
| Dimension | Supported | Not supported |
|---|---|---|
| FacturaScripts | 2025.6 → 2025.latest | < 2025.6 (blocked by facturascripts.ini::min_version) |
| PHP | 8.0, 8.1, 8.2 (CI matrix); 8.3 best-effort | < 8.0 |
| Moodle | 4.1 LTS + (MoodleClient::MIN_MOODLE_RELEASE = '4.1') |
4.0 flagged unsupported · < 4.0 blocked |
| MySQL / MariaDB | MySQL 5.7+, MariaDB 10.4+ | MySQL 5.6, MariaDB < 10.4 |
| PostgreSQL | 13+ | < 13 |
| Browsers | Chrome/Edge latest 2, Firefox latest 2, Safari 16+ | IE 11, Safari < 16 |
| cURL | >= 7.50 (HTTP/2 + modern TLS) | < 7.50 |
Combinations exercised by CI (.github/workflows/ci.yml):
- PHP 8.0 + FS 2025.6 + MySQL 8.0
- PHP 8.1 + FS 2025.81 + MySQL 8.0
- PHP 8.2 + FS 2025.81 + MySQL 8.0 (also emits coverage report)
- Copy the
MoodleManagementfolder into the FacturaScriptsPluginsdirectory - Enable the plugin from Admin > Plugins
- Configure at least one Moodle instance from Moodle Management > Moodle Instances
For the plugin to work correctly, you must create a web service in Moodle with the required functions and generate an access token.
- Go to Site administration > General > Advanced features
- Check Enable web services (
enablewebservices) - Save changes
- Go to Site administration > Server > Web services > Manage protocols
- Enable the REST protocol
- Go to Site administration > Users > Accounts > Add a new user
- Create a dedicated user (e.g.,
ws_facturascripts) - Assign the Manager role at system level:
- Site administration > Users > Permissions > Assign system roles
- Select Manager and add the created user
- Go to Site administration > Server > Web services > External services
- Click Add
- Configure:
- Name:
FacturaScripts Integration - Short name:
facturascripts - Enabled: Yes
- Authorised users only: Yes
- Name:
- Save
- In the service list, click Authorised users and add the service user created in Step 3
- In the service list, click Functions next to the
FacturaScripts Integrationservice - Add the following functions:
| Function | Description |
|---|---|
core_webservice_get_site_info |
Connection test and site information |
| Function | Description |
|---|---|
core_user_get_users |
Search users |
core_user_get_users_by_field |
Get user by field |
core_user_create_users |
Create users |
core_user_update_users |
Update users |
core_user_delete_users |
Delete users |
| Function | Description |
|---|---|
core_cohort_get_cohorts |
Get cohorts |
core_cohort_search_cohorts |
Search cohorts |
core_cohort_create_cohorts |
Create cohorts |
core_cohort_update_cohorts |
Update cohorts |
core_cohort_delete_cohorts |
Delete cohorts |
core_cohort_add_cohort_members |
Add cohort members |
core_cohort_delete_cohort_members |
Remove cohort members |
core_cohort_get_cohort_members |
Get cohort members |
| Function | Description |
|---|---|
core_course_get_courses |
Get courses |
core_course_get_courses_by_field |
Get course by field |
core_course_search_courses |
Search courses |
core_course_create_courses |
Create courses |
core_course_update_courses |
Update courses |
core_course_delete_courses |
Delete courses |
core_course_duplicate_course |
Duplicate course |
core_course_get_contents |
Get course content |
core_course_get_categories |
Get categories |
core_course_create_categories |
Create categories |
core_course_update_categories |
Update categories |
core_course_delete_categories |
Delete categories |
| Function | Description |
|---|---|
core_course_get_course_module |
Module detail by cmid |
core_course_get_course_module_by_instance |
Module detail by type+instance |
core_course_get_course_content_items |
Available activity types |
core_courseformat_update_course |
Course editor actions (show/hide/move/duplicate/delete modules and sections, indentation, group mode) |
core_course_delete_modules |
Delete modules |
| Function | Description |
|---|---|
enrol_manual_enrol_users |
Manually enrol users |
enrol_manual_unenrol_users |
Unenrol users |
core_enrol_get_enrolled_users |
Get enrolled users in a course |
core_enrol_get_users_courses |
Get a user's courses |
core_enrol_get_course_enrolment_methods |
Course enrolment methods |
core_enrol_get_potential_users |
Potential users for enrolment |
core_enrol_search_users |
Search users for enrolment |
enrol_self_enrol_user |
Self-enrolment |
enrol_self_get_instance_info |
Self-enrolment info |
enrol_meta_add_instances |
Add meta-enrolments |
enrol_meta_delete_instances |
Remove meta-enrolments |
| Function | Description |
|---|---|
core_completion_get_activities_completion_status |
Activity completion status |
core_completion_get_course_completion_status |
Course completion status |
gradereport_user_get_grade_items |
User grade items per course |
| Function | Description |
|---|---|
core_badges_get_user_badges |
Get user badges |
| Function | Description |
|---|---|
core_group_get_course_groups |
List course groups |
core_group_create_groups |
Create groups |
core_group_update_groups |
Update groups |
core_group_delete_groups |
Delete groups |
core_group_get_group_members |
Get group members |
core_group_add_group_members |
Add group members |
core_group_delete_group_members |
Remove group members |
| Function | Description |
|---|---|
core_message_send_instant_messages |
Send instant messages to users |
core_message_get_conversation_between_users |
Get conversation between two users |
core_message_get_conversation_messages |
Get messages from a conversation |
core_message_send_messages_to_conversation |
Send message to an existing conversation |
core_message_get_conversations |
List user conversations (conversations hub) |
core_message_get_unread_conversations_count |
Count conversations with unread messages (navbar badge) |
core_message_mark_all_conversation_messages_as_read |
Mark all messages in a conversation as read |
| Function | Description |
|---|---|
core_notes_create_notes |
Create notes on user profile |
core_notes_get_course_notes |
Get notes for a course/user |
core_notes_delete_notes |
Delete notes |
| Function | Description |
|---|---|
core_calendar_get_calendar_events |
Get calendar events |
core_calendar_create_calendar_events |
Create calendar events |
core_calendar_delete_calendar_events |
Delete calendar events |
| Function | Description |
|---|---|
core_role_assign_roles |
Assign roles |
core_role_unassign_roles |
Unassign roles |
- Go to Site administration > Server > Web services > Manage tokens
- Click Create token
- Select the service user (e.g.,
ws_facturascripts) - Select the service:
FacturaScripts Integration - Save and copy the generated token
- In FacturaScripts, go to Moodle Management > Moodle Instances
- Click + New
- Fill in:
- Site name: A descriptive name
- URL: Full Moodle URL (e.g.,
https://myacademy.com/moodle) - Token: Paste the token generated in Step 6
- Save and click Test Connection to verify
The messaging system enables bidirectional communication between FacturaScripts and Moodle users. Messages are sent and received through the WS service user (acting as "support").
-
WS functions registered: Make sure the 7 messaging functions are added to the WS service in Moodle (see Step 5 - Messaging):
core_message_send_instant_messagescore_message_get_conversation_between_userscore_message_get_conversation_messagescore_message_send_messages_to_conversationcore_message_get_conversations(conversations hub)core_message_get_unread_conversations_count(navbar badge)core_message_mark_all_conversation_messages_as_read(mark as read)
-
Messaging enabled in Moodle: Verify that messaging is active in Site administration > General > Advanced features > Enable messaging (
messaging). -
WS user permissions: The service user must have the capabilities:
moodle/site:sendmessage— send messagesmoodle/site:readallmessages— read conversations (normally included in the Manager role)
- Go to Moodle Management > Moodle Instances and edit your instance
- Click Test Connection — this automatically retrieves and stores the
service_userid(the WS user's ID in Moodle), required to identify the sender in the chat - Verify that the Service User ID field shows a numeric value in the instance form
- Go to Moodle Management > Moodle Users and open a user mapping
- Click the Chat tab
- If no previous conversation exists, you'll see an empty chat ready to send the first message — the conversation is created automatically in Moodle upon sending
- Type your message and press Enter or the send button
- Sent messages appear as green bubbles (WhatsApp-style); user replies appear as white bubbles with the FS contact name
- The chat auto-refreshes every 5 seconds — no need to reload the page to see new messages
Note: You can also send a quick message using the Send Message button on the user's main tab (opens a modal).
- Go to Moodle Management > Moodle Courses and open a course
- Click the Messaging tab
- Select the recipient mode:
- All enrolled: sends to all active enrolled users in the course
- Selected users: allows choosing specific recipients from the list
- Type the message and click Send Message
- Click the chat icon in the top navigation bar (shows a red badge with the unread message count)
- You'll see a list of all open conversations across all active Moodle instances
- Conversations with unread messages appear first, marked with a red semaphore and a count badge
- Use the filter buttons: All, Unread Only, or Read Only to narrow the list
- Click any conversation to go directly to the user's chat — messages are automatically marked as read
- Use New Conversation to start a chat with a mapped user who doesn't have an open conversation yet
- The conversation list auto-refreshes every 10 seconds
- The sender is always the WS service user — messages cannot be sent as another user
- Only conversations involving the WS user can be read (no access to third-party conversations)
- Chat auto-refresh queries the Moodle API every 5 seconds; it pauses automatically when the browser tab is not visible
- The navbar badge refreshes every 30 seconds
@since 2.0 — V2.0-ACTION-PLAN F11.1 · §9.1
| Area | Limitation | Tracking |
|---|---|---|
| Webhooks | The receiver expects payloads in the plugin's internal format (see docs/EVENTS.md). Moodle does not emit webhooks natively; a bridge (Event Observer + curl) is required. |
v2.1 — reference PHP bridge in docs. |
| Trash | The trash viewer (F10.4) supports restore/purge but the primary List views still perform physical delete. For bulk soft-delete, set deleted_at via SQL or a dedicated worker. |
v2.1 — execBeforeDelete hook in models. |
| Dashboard | The dashboard caches its payload for 60 s (F10.9). After a bulk sync use ?refresh=1 to force a fresh read. |
Documented in-place. |
| Username alias | random_alias applies only to newly created accounts. Users already mapped with a name-based username keep it — to change, un-enrol, rename in Moodle, and re-map. |
v2.1 — rename wizard. |
| Localisation | Translations cover ES variants + EN + FR + PT(PT/BR) + IT + DE + CA + GL + EU + CA-VL + PL + CS. Missing locales fall back to English. | Open PR — additional languages welcome. |
| Browsers | Chart.js 4.x (F3.1) requires Chrome/Edge latest 2, Firefox latest 2, Safari 16+. IE11 is not supported. | Constraint formalised in docs/SUPPORTED-VERSIONS.md. |
| Minimum Moodle | Moodle 4.1 LTS. Instances on 4.0 are flagged status=unsupported automatically; < 4.0 is blocked (see MoodleClient::MIN_MOODLE_RELEASE). |
Stable policy. |
| MoodleClient | Legacy god class (~1600 LOC). Fase 8 introduced namespaced facades (Lib/Moodle/Api/*); caller migration is gradual. |
v2.2 — direct-call deprecation after 6-month grace period. |
| Certificates | The PDF generator uses Cezpdf (FS core dep) with ROT50/Template simple skins. Full HTML/CSS templates are backlogged. | v2.1 — Twig + wkhtmltopdf renderer. |
| Concurrency | Cooperative locks (Lib/Cron/Lock) use GET_LOCK / pg_try_advisory_lock. Under SQLite (tests only) the locks are no-ops. |
By design — SQLite is test-only. |
See also: docs/TROUBLESHOOTING.md, UPGRADE.md, docs/SUPPORTED-VERSIONS.md.
Spanish (ES, AR, CL, CO, CR, DO, EC, GT, MX, PA, PE, UY), English, French, Portuguese (PT, BR), Italian, German, Catalan, Galician, Basque, Valencian, Polish, and Czech.
If you need a custom integration with your LMS platform or additional features for your organization, feel free to contact us:
- Email: dfelipe.monroyc@gmail.com
- Web: diegomonroydev.com
LGPL v3 - GNU Lesser General Public License