Table of Contents

Namespace KadicErp.WebApi.Controllers.Academy

Classes

AcademicPeriodsController

Períodos académicos (decisiones del owner, 13/08/2026 — spec-periodo-academico): catálogo por Tenant+Sucursal (P6) con solapamiento permitido (P5). El listado con branchId alimenta el selector del wizard de inscripción y el filtro del hub; el CRUD es la pantalla de administración (Master Data), mismo molde que Disciplines.

AcademyGendersController

Fase 2 (§2.1, 05/08/2026) — core.Gender alcanzable desde ACADEMY para poblar el selector de género del wizard de alumno (antes 'M'/'F' hardcodeado en el front; ahora StudentProfile exige GenderId real). Mismo patrón que AcademyPaymentMethodsController.

AcademyPaymentMethodsController

US#0 CA14 — core.PaymentMethods alcanzable desde el módulo ACADEMY. El único endpoint existente (GET api/sales/payment-methods) está tras [RequireModule("SALES")], inalcanzable para un tenant de academia sin Sales contratado. US#8/US#16 (registro de pago) dependen de este catálogo.

AcademySettingsController

US#26 (#8977, corrección de modelo del 02/08/2026) — Branch Defaults Academy. Configuración por Branch de prorrateo, make-ups, reservas, capacidad y comisiones. Consumida internamente por US#6/US#7/US#12/US#13/US#14/US#20 vía IAcademyBranchDefaultsResolver, nunca directo a academy.AcademyBranch (CA7).

AddClassScheduleItemBody
AddCommissionAdjustmentBody
AddSectionLevelBody
AddSkillBody
AddTutorBody
AssignClassScheduleBody
AutomationRuleBody
AutomationsController

US#17 (#8497) — Automatización de envíos WhatsApp por eventos del sistema. Las 7 rutas son exactamente las que automations.service.ts ya construye.

AvailabilitiesController

Catálogo global de días de la semana (decisión de David — "Availability debe ser una tabla donde se guarden Lunes, Martes...."). Solo lectura: son 7 filas fijas sembradas por migración, iguales para todos los tenants — sin CRUD, sin permisos propios (se gatea con el mismo permiso de lectura de Instructors, ya que su único consumidor hoy es el picker de disponibilidad del modal de Instructor).

CalculateCommissionsBody
ClassScheduleController

US#32 (#8990) — catálogo, asignación y adherencia del Programa de Clases. Renombrado de TrainingPlansController por US#39 (US-105, #9070) CA1: el nombre técnico ahora coincide con el nombre de negocio "Programa de Clases" (branding UI "360", fuera del código, DA-01). El registro por clase vive en SessionsController (embebido en el roster de asistencia de US#7, no en pantalla propia).

CollectionsController

US#8 (#8488) — Cobranza: deudores, pagos (parciales), planes y vista 360. Campos condicionados por permiso (ncf, saldos de la 360) van null, nunca se filtra la fila.

CommissionsController

US#20 (#8500) — liquidación de comisiones de instructores. Calcular reconstruye las líneas Pending de un período abierto; liquidar marca como pagado; cerrar el período congela todo (CA4, siempre manual).

CommunicationsController

US#10 (#8490) — Comunicaciones WhatsApp (plantillas + envío). Reusa la infraestructura de WhatsApp ya existente (IModuleNotificationDispatcher) — no se agrega ningún cliente HTTP.

CreateAcademicPeriodBody
CreateAndAssignLevelBody
CreateDisciplineBody
CreateEnrollmentBody
CreateExerciseBody
CreateRelationshipBody
CreateSpecialtyBody
CreateTransferBody
CreateTutorTypeBody
DisciplinesController

US#1 (#8481) Task #8875, addendum 07/08/2026 — CRUD completo del catálogo de disciplinas. Separado de ProgramsController (donde vivía como sub-recurso con solo Create+GetAll, reusando permisos de Programs) para tener permisos propios (Academy.Disciplines) y una pantalla de administración en Master Data → Catálogo.

EmergencyContactBodyItem
EnrollmentsController

US#6 (#8486) — inscripciones: wizard (Alumno→Grupo→Resumen) y hub. El importe sale siempre de quote (GET, no persiste); el alta real vive en POST /enrollments.

ExerciseCatalogBody
ExerciseCatalogController

US#40 (US-106, #9071) — CRUD del catálogo reutilizable de ejercicios (tipo, distancia, tiempo objetivo y repeticiones), para no retipear el mismo ejercicio en cada Programa de Clases o en una sustitución ad-hoc. Baja lógica (IsActive) vía el endpoint DELETE.

ExportReportBody
FamiliesController

US#4 — familias: listado, ficha y estado de cuenta. US#5 (#8485) añade el alta atómica (POST /families, POST /families/{id}/students) — el resto de la frontera sigue vigente.

FreezeBody
FreezesController

US#13 (#8493) — Congelar inscripción. Las 3 rutas son exactamente las que freezes.service.ts ya construye — no se inventan rutas nuevas ni se cambia POST por PATCH.

GroupsController

US#46 (US-201, #9077) — CRUD del Grupo (padre, patrón de días). Reemplaza el CRUD viejo que, desde US#35 (US-101), seguía apuntando a la composición Group+Section+SectionLevel para no romper el contrato plano congelado. GetSchedule/CheckConflicts se mudaron a SectionsController (US#47, US-202) — siempre operaron sobre horario/conflictos de Sección, no de Grupo; vivían aquí solo porque US-202 no existía todavía.

InstructorsController

US#25 — catálogo mínimo de instructores. Desbloquea US#3 (creación de grupos), que exige instructorId. US#19 (#8499) enriquece el DTO, añade /agenda y los campos ricos de alta/edición — mismo controlador, misma tabla, sin duplicar nada.

IssueCertificateBody
LaneHistoryController

US#36 (US-102, #9067) CA5 — consulta del historial de carril usado por Sesión x Nivel, para trazabilidad histórica.

LevelsController

US#2 — niveles del "camino del alumno" y su malla de habilidades. La regla dura del módulo: SkillId es inmutable, reordenar solo toca Order (CA3/CA6).

MakeupsController

US#14 (#8494) — Make-ups (recuperación de clases). Los verbos siguen exactamente lo que makeups.service.ts ya construye: PATCH para las acciones (a diferencia de US#13, que usa POST) — se respeta lo declarado por cada servicio del front, no se homogeniza.

MarkAttendanceBody
OnboardingController

US#8989 (Academy US#31) — wizard de onboarding del tenant (5 pasos: Institución, Disciplinas, Modalidad, Configuración de cobro, Primer grupo). Corre una sola vez por tenant de Academia, la primera vez que el admin entra. Reemplaza el marcador POST /api/academies/onboarding que vivía en EnrollmentsController sin estado persistido ni pasos reales.

OverrideLaneBody
PickupAuthorizationBodyItem
ProgramsController

US#1 — catálogo de programas. Bloquea a US#3 (grupos) y US#6 (inscripciones).

ProgressController

US#18 (#8498) — Progreso: matriz de habilidades, catálogo de ejercicios, bitácora de clases y certificados de nivel. Esta US no tenía servicio ni endpoints previos — el contrato completo se diseñó en la US misma.

RecordPlanExecutionBody
RegisterPaymentBody
RejectSessionReportBody
RelationshipsController

US#34 (#9050) — catálogo de parentesco (Padre, Madre, Tutor legal…), CRUD calcado de DisciplinesController.

ReorderLevelsBody
ReorderSkillsBody
ReparentResourceBody
ReportSessionBody
ReportsController

US#8502 — Galería de reportes operativos. View da acceso al catálogo, Preview a la vista previa (máximo 50 filas, resuelta en GetReportPreviewHandler) y Export a la descarga completa en CSV/Excel/PDF.

ResourcesController

US#11 (#8491, CA18/CA22) — árbol de recursos físicos por sede (Piscina → Carril). Sin ella, US#3 no detecta conflictos de recurso (CA6). [RequireTenantBranch] aislamiento por sucursal; el aislamiento por sede (VenueId) lo resuelven los handlers vía tenant + pertenencia.

RunRollingChargesBody
SaveClassLogBody
SaveClassLogExerciseBody
SaveOnboardingStepBody
ScheduleMakeupBody
SeatReservationsController

US#6 (#8486) Decisión 3 — apartar/liberar plaza (academy.SeatReservation, Reason=PRE_ENROLLMENT). Comparte la entidad con US#13 (Reason=FREEZE).

SectionInstructorsController

US#65 — asignación N:N Sección↔Instructor. Recurso propio, distinto de SectionsController (CRUD de la Sección, ya no toca instructor) y InstructorsController (perfil/catálogo del instructor) — CA9/CA10 son instructor-céntricas, CA11 es group-céntrica, ninguna encaja 100% en los otros dos controladores.

SectionsController

US#47 (US-202, #9078) — CRUD de la Sección (horario dentro de un Grupo) + sus SectionLevel (nivel + carril por defecto), con detección de conflictos de horario/carril y validación de capacidad de carril ≤ capacidad de piscina.

GetSchedule/CheckConflicts se mudan aquí desde GroupsController (US#46 los había dejado ahí con el comentario "US-202, no tocar"): ya operaban sobre Section/ SectionLevel desde US#35 (US-101) — vivían mal ubicados bajo el Grupo. CheckConflicts se reemplaza por CheckSectionConflictsCommand, con granularidad real por Nivel/carril en vez del ResourceId único que exigía el contrato viejo de Grupo.

SendBody
SendReminderBody
SessionReportsController

US#20 (#8500) CA5 — reporte + aprobación de sesiones cerradas, la base de la elegibilidad de pago que CalculateCommissionsHandler consulta.

SessionsController

US#7 (#8487) — asistencia (roster diario). Contrato 100% nuevo: ninguna de estas rutas existía en el frontend antes de esta US.

SetAcademicPeriodActiveBody
SetActiveBody
SetDisciplineActiveBody
SetGroupActiveBody
SetInstructorActiveBody
SetProgramActiveBody
SetRelationshipActiveBody
SetResourceActiveBody
SetSectionActiveBody
SetSkillsBody
SetSpecialtyActiveBody
SetTutorTypeActiveBody
SetVenueActiveBody
SpecialtiesController

Catálogo de especialidades de Instructor, por tenant (decisión de David — "Speciality debe ser un CATALOGO y aquí un DropDown que se alimente de ese catálogo"). Mismo molde que DisciplinesController.

StudentsController

US#5 — expediente completo del alumno: perfil, datos médicos, contactos de emergencia, autorizados a recoger y tarjeta de seguridad auditada. CA13: el alta con alumnos vive en FamiliesController (POST /families, POST /families/{id}/students), que es US#5, no US#4.

SubstitutePlanExerciseBody
TemplateBody
ToggleAutomationRuleBody
ToggleTemplateBody
TransfersController

US#12 (#8492) — Transferir alumno entre grupos. CA12: no hay flujo de aprobación, POST /transfers ejecuta de inmediato y es irreversible — la confirmación vive en el cliente.

TutorTypesController

US#34 (#9050) — catálogo de tipo de tutor (Económico, Contacto de emergencia, Autorizado para recoger, Legal…), CRUD calcado de DisciplinesController.

UpdateAcademicPeriodBody
UpdateClassScheduleBody
UpdateDisciplineBody
UpdateEmergencyContactsBody
UpdateFamilyBody
UpdateGroupBody
UpdateInstructorBody
UpdateLevelBody
UpdatePickupAuthorizationsBody
UpdateProgramBody
UpdateRelationshipBody
UpdateResourceBody
UpdateSectionBody
UpdateSpecialtyBody
UpdateStudentBody

Fase 3 (12/08/2026) — dejó de traer Name/Birth/GenderId: se resuelven siempre desde el Business Partner vinculado del alumno, ya no son editables desde este endpoint.

UpdateStudentMedicalBody
UpdateStudentSkillBody
UpdateTutorTypeBody
UpdateVenueBody
VenuesController

US#11 (#8491, CA16/CA22) — catálogo de Sedes (academy.Venue), entidad propia con FK al Branch de core. [RequireTenantBranch] es obligatorio: una Venue cuelga siempre de la sucursal fiscal resuelta en el token, igual que RentCarBranchConfigController. Reemplaza al antiguo BranchesController, que exponía AcademyBranch como si fuera la sede — no lo era (ver Docs/Academy/DECISIONES-02-08-2026.md §1).

VoidPaymentBody
WaitlistController

US#3 (#8483) — lista de espera por grupo.