Mario Martínez Hernández 2 недель назад
Родитель
Сommit
6114cf1006
5 измененных файлов с 3548 добавлено и 75 удалено
  1. 109 0
      reporte_config.md
  2. 226 75
      reporte_domain.md
  3. 143 0
      reporte_general.md
  4. 1420 0
      reporte_service.md
  5. 1650 0
      reporte_web.md

+ 109 - 0
reporte_config.md

@@ -0,0 +1,109 @@
+# 📁 Reporte de carpeta: `config`
+
+> Detalle de clases, métodos y comentarios extraídos automáticamente
+
+
+### 🧩 Clase: `ApplicationLocaleResolver`
+**Ubicación:** `src\main\java\es\uv\saic\config\ApplicationLocaleResolver.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `resolveLocale()` — ⚪ Interno
+- `setLocale()` — ⚪ Interno
+- `determineDefaultLocale()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `AuthSuccessHandler`
+**Ubicación:** `src\main\java\es\uv\saic\config\AuthSuccessHandler.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `onAuthenticationSuccess()` — ⚪ Interno
+```
+//360
+```
+- `if()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `Globals`
+**Ubicación:** `src\main\java\es\uv\saic\config\Globals.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+//private String filePath = "/DATA/saic-data/files/";
+```
+- `getFilePath()` — ⚪ Interno
+- `getFileName()` — ⚪ Interno
+- `getCurrentYear()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `SchedulerConfig`
+**Ubicación:** `src\main\java\es\uv\saic\config\SchedulerConfig.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `configureTasks()` — ⚪ Interno
+- `ThreadPoolTaskScheduler()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `SecurityConfig`
+**Ubicación:** `src\main\java\es\uv\saic\config\SecurityConfig.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `filterChain()` — ⚪ Interno
+- `AuthSuccessHandler()` — ⚪ Interno
+- `hasIpAddress()` — ⚪ Interno
+- `IpAddressMatcher()` — ⚪ Interno
+- `AuthorizationDecision()` — ⚪ Interno
+- `authenticationManager()` — ⚪ Interno
+- `sessionRegistry()` — ⚪ Interno
+- `SessionRegistryImpl()` — ⚪ Interno
+- `contextSource()` — ⚪ Interno
+- `DefaultSpringSecurityContextSource()` — ⚪ Interno
+- `passwordEncoder()` — ⚪ Interno
+- `BCryptPasswordEncoder()` — ⚪ Interno
+- `httpSessionEventPublisher()` — ⚪ Interno
+- `HttpSessionEventPublisher()` — ⚪ Interno
+- `concurrentSession()` — ⚪ Interno
+- `ConcurrentSessionControlAuthenticationStrategy()` — ⚪ Interno
+- `SessionFixationProtectionStrategy()` — ⚪ Interno
+- `RegisterSessionAuthenticationStrategy()` — ⚪ Interno
+- `CompositeSessionAuthenticationStrategy()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `WebConfig`
+**Ubicación:** `src\main\java\es\uv\saic\config\WebConfig.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `localeResolver()` — ⚪ Interno
+- `ApplicationLocaleResolver()` — ⚪ Interno
+- `localeChangeInterceptor()` — ⚪ Interno
+- `LocaleChangeInterceptor()` — ⚪ Interno
+- `addInterceptors()` — ⚪ Interno
+- `forwardedHeaderFilter()` — ⚪ Interno
+- `ForwardedHeaderFilter()` — ⚪ Interno
+
+---
+
+
+# 📈 Estadísticas finales
+
+- Total de clases: 6
+- Total de métodos: 37
+- Total de comentarios: 2
+
+✅ **Fin del reporte de carpeta.**

Разница между файлами не показана из-за своего большого размера
+ 226 - 75
reporte_domain.md


+ 143 - 0
reporte_general.md

@@ -0,0 +1,143 @@
+# 🧾 Reporte General de Clases Java
+
+> Control de revisión y estructura por carpetas
+
+
+## 📂 Carpeta: `config`
+
+- `ApplicationLocaleResolver` — ⚠️ *Pendiente*
+- `AuthSuccessHandler` — ⚠️ *Pendiente*
+- `Globals` — ⚠️ *Pendiente*
+- `SchedulerConfig` — ⚠️ *Pendiente*
+- `SecurityConfig` — ⚠️ *Pendiente*
+- `WebConfig` — ⚠️ *Pendiente*
+
+## 📂 Carpeta: `domain`
+
+- `Acreditacio` — ⚠️ *Pendiente*
+- `AcreditacioPK` — ⚠️ *Pendiente*
+- `AcreditacioTransfer` — ⚠️ *Pendiente*
+- `AnyDimensioDTO` — ⚠️ *Pendiente*
+- `Calendari` — ⚠️ *Pendiente*
+- `Categoria` — ⚠️ *Pendiente*
+- `CategoriaDocumentDTO` — ⚠️ *Pendiente*
+- `CategoriaPareDTO` — ⚠️ *Pendiente*
+- `Datasource` — ⚠️ *Pendiente*
+- `DimensioInstanciesDTO` — ⚠️ *Pendiente*
+- `Dimension` — ⚠️ *Pendiente*
+- `Indicador` — ⚠️ *Pendiente*
+- `CursoValor` — ⚠️ *Pendiente*
+- `Document` — ⚠️ *Pendiente*
+- `DocumentDTO` — ⚠️ *Pendiente*
+- `DocumentTemplate` — ⚠️ *Pendiente*
+- `DummyDataTransfer` — ⚠️ *Pendiente*
+- `Email` — ⚠️ *Pendiente*
+- `EvidenciaIndicadorEnquesta` — ⚠️ *Pendiente*
+- `EvidenciaIndicadorEnquestaPK` — ⚠️ *Pendiente*
+- `EvidenciaTransfer` — ⚠️ *Pendiente*
+- `Grafica` — ⚠️ *Pendiente*
+- `GraficaPK` — ⚠️ *Pendiente*
+- `Indicador` — ⚠️ *Pendiente*
+- `CursoValor` — ⚠️ *Pendiente*
+- `IndicadorEnquesta` — ⚠️ *Pendiente*
+- `IndicadorEnquestaTmp` — ⚠️ *Pendiente*
+- `Informe` — ⚠️ *Pendiente*
+- `InformeProcesPK` — ⚠️ *Pendiente*
+- `InformeProcessos` — ⚠️ *Pendiente*
+- `Instancia` — ⚠️ *Pendiente*
+- `InstanciaDTO` — ⚠️ *Pendiente*
+- `InstanciaGanttDTO` — ⚠️ *Pendiente*
+- `FROM` — ⚠️ *Pendiente*
+- `InstanciaTasca` — ⚠️ *Pendiente*
+- `InstanciaTascaTransfer` — ⚠️ *Pendiente*
+- `InstanciaTascaVer` — ⚠️ *Pendiente*
+- `InstanciaTascaVerPK` — ⚠️ *Pendiente*
+- `InstanciaTascaVersioTransfer` — ⚠️ *Pendiente*
+- `InstanciaTransfer` — ⚠️ *Pendiente*
+- `Link` — ⚠️ *Pendiente*
+- `Noticia` — ⚠️ *Pendiente*
+- `Organ` — ⚠️ *Pendiente*
+- `OrganEquivalent` — ⚠️ *Pendiente*
+- `OrganEquivalentPK` — ⚠️ *Pendiente*
+- `OrganPK` — ⚠️ *Pendiente*
+- `Plantilla` — ⚠️ *Pendiente*
+- `PlantillaComentario` — ⚠️ *Pendiente*
+- `PlantillaConversation` — ⚠️ *Pendiente*
+- `Proces` — ⚠️ *Pendiente*
+- `Rol` — ⚠️ *Pendiente*
+- `ScheduledTasks` — ⚠️ *Pendiente*
+- `SupervisionSearchParams` — ⚠️ *Pendiente*
+- `SysStatus` — ⚠️ *Pendiente*
+- `Tasca` — ⚠️ *Pendiente*
+- `TascaVersioTransfer` — ⚠️ *Pendiente*
+- `Tipus` — ⚠️ *Pendiente*
+- `TreeDTOAny` — ⚠️ *Pendiente*
+- `TreeDTODimensio` — ⚠️ *Pendiente*
+- `TreeDTOInstancia` — ⚠️ *Pendiente*
+- `TreeDTOOrgan` — ⚠️ *Pendiente*
+- `Usuari` — ⚠️ *Pendiente*
+- `UsuarisRol` — ⚠️ *Pendiente*
+- `Wiki` — ⚠️ *Pendiente*
+
+## 📂 Carpeta: `service`
+
+- `AcreditacioService` — ⚠️ *Pendiente*
+- `AuthProvider` — ⚠️ *Pendiente*
+- `CalendariService` — ⚠️ *Pendiente*
+- `CategoriaService` — ⚠️ *Pendiente*
+- `DataService` — ⚠️ *Pendiente*
+- `DatasourceService` — ⚠️ *Pendiente*
+- `DocumentService` — ⚠️ *Pendiente*
+- `EmailService` — ⚠️ *Pendiente*
+- `EvidenciaIndicadorEnquestaService` — ⚠️ *Pendiente*
+- `GraficaService` — ⚠️ *Pendiente*
+- `IndicadorEnquestaService` — ⚠️ *Pendiente*
+- `IndicadorEnquestaTmpService` — ⚠️ *Pendiente*
+- `IndicadorService` — ⚠️ *Pendiente*
+- `InformeService` — ⚠️ *Pendiente*
+- `InstanciaService` — ⚠️ *Pendiente*
+- `InstanciaTascaService` — ⚠️ *Pendiente*
+- `InstanciaTascaVerService` — ⚠️ *Pendiente*
+- `LinkService` — ⚠️ *Pendiente*
+- `NoticiaService` — ⚠️ *Pendiente*
+- `OrganService` — ⚠️ *Pendiente*
+- `ParserService` — ⚠️ *Pendiente*
+- `PlantillaService` — ⚠️ *Pendiente*
+- `ProcesService` — ⚠️ *Pendiente*
+- `RolService` — ⚠️ *Pendiente*
+- `SysStatusService` — ⚠️ *Pendiente*
+- `TascaService` — ⚠️ *Pendiente*
+- `TipusService` — ⚠️ *Pendiente*
+- `UsuariService` — ⚠️ *Pendiente*
+- `UsuarisRolService` — ⚠️ *Pendiente*
+- `WikiService` — ⚠️ *Pendiente*
+
+## 📂 Carpeta: `web`
+
+- `AdminController` — ⚠️ *Pendiente*
+- `AjaxController` — ⚠️ *Pendiente*
+- `DashboardController` — ⚠️ *Pendiente*
+- `DataController` — ⚠️ *Pendiente*
+- `DownloadController` — ⚠️ *Pendiente*
+- `ExportController` — ⚠️ *Pendiente*
+- `IndexController` — ⚠️ *Pendiente*
+- `KeepAliveController` — ⚠️ *Pendiente*
+- `LoginController` — ⚠️ *Pendiente*
+- `ManagersController` — ⚠️ *Pendiente*
+- `ParseController` — ⚠️ *Pendiente*
+- `ProceduresController` — ⚠️ *Pendiente*
+- `ActiveSession` — ⚠️ *Pendiente*
+- `PendingEmail` — ⚠️ *Pendiente*
+- `StatsController` — ⚠️ *Pendiente*
+- `SupervisionController` — ⚠️ *Pendiente*
+- `TestController` — ⚠️ *Pendiente*
+- `WikiController` — ⚠️ *Pendiente*
+
+# 📊 Resumen General
+
+- `config`: 6 clases, 37 métodos, 2 comentarios
+- `domain`: 64 clases, 1118 métodos, 0 comentarios
+- `service`: 30 clases, 438 métodos, 8 comentarios
+- `web`: 18 clases, 347 métodos, 112 comentarios
+
+**Total general:** 118 clases | 1940 métodos | 122 comentarios detectados**

+ 1420 - 0
reporte_service.md

@@ -0,0 +1,1420 @@
+# 📁 Reporte de carpeta: `service`
+
+> Detalle de clases, métodos y comentarios extraídos automáticamente
+
+
+### 🧩 Clase: `AcreditacioService`
+**Ubicación:** `src\main\java\es\uv\saic\service\AcreditacioService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getById()` — ⚪ Interno
+- `AcreditacioPK()` — ⚪ Interno
+- `getAll()` — ⚪ Interno
+- `getNextsCurrentYear()` — ⚪ Interno
+- `getByCursGrup()` — ⚪ Interno
+- `getByCursGrupTambit()` — ⚪ Interno
+- `getByCurs()` — ⚪ Interno
+- `getByOrgan()` — ⚪ Interno
+- `getByCentre()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `AuthProvider`
+**Ubicación:** `src\main\java\es\uv\saic\service\AuthProvider.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `authenticate()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `UsernamePasswordAuthenticationToken()` — ⚪ Interno
+- `BadCredentialsException()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `InitialDirContext()` — ⚪ Interno
+- `SearchControls()` — ⚪ Interno
+- `BadCredentialsException()` — ⚪ Interno
+- `BadCredentialsException()` — ⚪ Interno
+- `BadCredentialsException()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `SimpleGrantedAuthority()` — ⚪ Interno
+- `UsernamePasswordAuthenticationToken()` — ⚪ Interno
+- `AuthenticationServiceException()` — ⚪ Interno
+- `BadCredentialsException()` — ⚪ Interno
+- `supports()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `CalendariService`
+**Ubicación:** `src\main\java\es\uv\saic\service\CalendariService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getAll()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+- `getNextEvents()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `CategoriaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\CategoriaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getAll()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+- `findFirstLevel()` — ⚪ Interno
+- `findFirstLevelAndU()` — ⚪ Interno
+- `findByTipusTambit()` — ⚪ Interno
+- `findByTipusTambitAndU()` — ⚪ Interno
+- `findByPareTambit()` — ⚪ Interno
+- `findByPareTambitAndU()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `DataService`
+**Ubicación:** `src\main\java\es\uv\saic\service\DataService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `DataService()` — ⚪ Interno
+- `doImport()` — ⚪ Interno
+- `StringBuilder()` — ⚪ Interno
+```
+/*  1) Comprobar columnas obligatorias  */
+List<String> mandatoryColumns = new ArrayList<String>();
+List<String> knownColumns = new ArrayList<String>();
+if(clau.equals("ruct")) {
+this.setColumnsRuct(ambit, knownColumns, mandatoryColumns);
+}
+else {
+this.setColumnsCod(ambit, knownColumns, mandatoryColumns);
+}
+
+if(!this.checkColumns(header, mandatoryColumns, errors, locale)) {
+return errors.append("[ERROR] " + (locale.equals("es") ? "Se han encontrado errores en el fichero proporcionado. No se ha importado ningún registro. " : "S'han trobat errors al fitxer proporcionat. No s'ha importat cap registre.")).append("<br>").toString();
+}
+
+/*  2) Eliminar las columnas obligatorias, conocidas e ignoradas. El resto se consideran indicadores a importar */
+knownColumns.addAll(mandatoryColumns);
+knownColumns.addAll(ignoredColumns);
+for(String c : knownColumns) {
+headerInds.removeIf(v->v.equalsIgnoreCase(c));
+}
+
+/*  3) Comprobar valores y tipos  */
+if(!this.checkValues(records, ambit, clau, errors, locale)) {
+return errors.append(("[ERROR] " + (locale.equals("es") ? "Se han encontrado errores en el fichero proporcionado. No se ha importado ningún registro. " : "S'han trobat errors al fitxer proporcionat. No s'ha importat cap registre."))).append("<br>").toString();
+}
+
+/*  4) Importar datos  */
+Integer numRecords = 0;
+Integer numTuples = 0;
+for (CSVRecord record : records) {
+Map<String, String> recordMap = new LinkedCaseInsensitiveMap<>();
+recordMap.putAll(record.toMap());
+String c = ambit.equals("T") || ambit.equals("C") ? translateCentre(recordMap.get("centre")) : null;
+String t = ambit.equals("T") ? translateTitulacio(recordMap.get("titulacio")) : null;  
+String type = recordMap.get("tipus");
+Integer curs = Integer.parseInt(recordMap.get("curs").replaceAll("\\D+",""));
+
+String cursEnquesta = recordMap.containsKey("curs_enquesta") ? recordMap.get("curs_enquesta") : null;
+    String titulacioOrigen = recordMap.containsKey("titulacio_origen") ? recordMap.get("titulacio_origen") : null;
+    String centreOrigen = recordMap.containsKey("centre_origen") ? recordMap.get("centre_origen") : null;
+    Integer nenq = recordMap.containsKey("nenq") ? Integer.parseInt(recordMap.get("nenq").replaceAll("\\D+","")) : null;
+    String ructStr = recordMap.containsKey("ruct") ? recordMap.get("ruct").replaceAll("\\D+","") : null;
+String cursd = recordMap.containsKey("cursd") ? recordMap.get("cursd") : null;
+    Integer ruct = null;
+    
+    if(ructStr != null) {
+    if(!(ructStr.isBlank() || ructStr.isEmpty() || ructStr.equals("NULL") || ructStr.equals("null"))) {
+    ruct = Integer.parseInt(ructStr);
+}
+    }
+
+Integer centre;
+    Integer titulacio;
+if(clau.equals("ruct") && ambit.equals("T") && ruct != null) {
+Organ o = this.orgs.findByRuct(ruct);
+if(o == null) {
+errors.append("[WARNING] " + (locale.equals("es") ? "No se ha encontrado el RUCT "+ructStr+", se omiten los registros de esta entrada." : "No s'ha trobat el RUCT "+ructStr+", s'ometen els registres d'aquesta entrada.")).append("<br>").toString();
+continue;
+}
+titulacio = o.getId().getLugar();
+centre = o.getOrgan().getId().getLugar();
+}
+else{
+centre = ambit.equals("T") || ambit.equals("C") ? Integer.parseInt(c.replaceAll("\\D+","")) : null;
+    titulacio = ambit.equals("T") ? Integer.parseInt(t) : null;
+if(!this.orgs.exists("T", titulacio)){
+errors.append("[WARNING] " + (locale.equals("es") ? "No se ha encontrado la titulación con código "+titulacio+" pero se importa igualmente." : "No s'ha trobat la titulació amb codi "+titulacio+" però s'importa igualment")).append("<br>").toString();
+}
+}
+    
+    if(header.contains("cursd")) {
+    cursd = recordMap.get("cursd").replaceAll("\\D+","");
+    }
+for(String r : headerInds) {
+IndicadorEnquestaTmp ie = new IndicadorEnquestaTmp();
+        ie.setEnquesta(enquesta);
+    ie.setTitulacio(titulacio);
+    ie.setCentre(centre);
+    ie.setCurs(curs);
+    ie.setAmbit(ambit); 
+    ie.setEstudi(estudi);
+        ie.setIndicador(r.replace("_min", "").replace("_max", "").toLowerCase());
+        ie.setNum(null);
+        ie.setCursd(cursd);
+        ie.setTipus(type);
+        ie.setUsuari(usuari.getUsuari());
+        ie.setData(new Timestamp(System.currentTimeMillis()));
+        ie.setCursEnquesta(cursEnquesta);
+        ie.setTitulacioOrigen(titulacioOrigen);
+        ie.setCentreOrigen(centreOrigen);
+        ie.setNenq(nenq);
+        ie.setRuct(ruct);
+        
+        try {
+        ie.setValor(record.get(r).replace(",", "."));
+        }
+        catch(Exception ex) {
+        ie.setValor(null);
+        }
+        
+        iets.save(ie);
+        numRecords++;
+}
+numTuples++;
+}
+
+/*  5) Notificar administradores y usuario implicado  */
+this.sendNotificacion(usuari, enquesta, ambit, estudi);
+if(!usuari.isAdmin()){
+this.sendConfirmation(usuari.getUsuari(), enquesta, ambit, estudi);
+}
+
+errors.append("[INFO] " + (locale.equals("es") ? ("Se han importado "+numRecords.toString()+" nuevos registros para un total de "+numTuples.toString()+" titulaciones") : ("[INFO] S'han importat "+numRecords.toString()+" nous registres per a un total de "+numTuples.toString()+" titulacions")));
+return errors.toString();
+}
+
+public String doDbImport(Integer dbOrigen, String vista, Integer srcCurs, Integer dstCurs, Usuari usuari, String enquesta, String ambit, 
+ String estudi, String locale, String clau, List<String> ignoredColumns) throws SQLException, ClassNotFoundException {
+
+StringBuilder errors = new StringBuilder();
+Datasource source = this.dss.findById(dbOrigen);
+if(source == null){
+return errors.append("[ERROR] " + (locale.equals("es") ? "No se ha proporcionado un origen de datos válido." : "No s'ha proporcionat un origen de dades vàlid.")).append("<br>").toString();
+}
+String query = "SELECT * FROM "+vista+ " WHERE curs = "+srcCurs;
+Class.forName(source.getDriver());
+Integer numRecords = 0;
+Integer numTuples = 0;
+try (Connection connection = DriverManager.getConnection(source.getConn())) {
+
+/*  1) Ejecutar consulta  */
+Statement statement = connection.createStatement();
+ResultSet resultset = statement.executeQuery(query);
+
+ResultSetMetaData resultMetadata = resultset.getMetaData();
+int columns = resultMetadata.getColumnCount();
+
+/*  2) Obtener resultados para procesar online y cerrar conexión  */
+RowSetFactory factory = RowSetProvider.newFactory();
+CachedRowSet result = factory.createCachedRowSet();
+result.populate(resultset);
+connection.close();
+
+/*  3) Comprobar columnas obligatorias  */
+List<String> mandatoryColumns = new ArrayList<String>();
+List<String> knownColumns = new ArrayList<String>();
+if(clau.equals("ruct")) {
+this.setColumnsRuct(ambit, knownColumns, mandatoryColumns);
+}
+else {
+this.setColumnsCod(ambit, knownColumns, mandatoryColumns);
+}
+
+List<String> allColNames = new ArrayList<String>();
+for(int i = 1; i <= columns; i++){
+allColNames.add(resultMetadata.getColumnLabel(i).toLowerCase());
+}
+List<String> colnames = new ArrayList<String>(allColNames);
+
+if(!this.checkColumns(colnames, mandatoryColumns, errors, locale)) {
+return errors.append("[ERROR] " + (locale.equals("es") ? "Se han encontrado errores al procesar la vista seleccionada. No se ha importado ningún registro. " : "S'han trobat errors al processar la vista seleccionada. No s'ha importat cap registre.")).append("<br>").toString();
+}
+
+knownColumns.addAll(mandatoryColumns);
+knownColumns.addAll(ignoredColumns);
+for(String c : knownColumns) {
+colnames.removeIf(v->v.equalsIgnoreCase(c));
+}
+
+if(ambit.equals("T") && !clau.equals("ruct")){
+return errors.append("[ERROR] " + (locale.equals("es") ? "Los datos de titulación deben de importarse por código RUCT" : "Les dades de titulació s'han d'importar per códi RUCT.")).append("<br>").toString();
+}
+
+/*  4) Importar datos  */
+while(result.next()) {
+Integer ruct = null;
+Integer titulacio = null;
+Integer centre = null;
+String c = ambit.equals("C") ? translateCentre(result.getString("centre")) : null;
+boolean isValid = true; 
+
+if(ambit.equals("T")) {
+String ructStr = result.getString("ruct");
+if(ructStr != null) {
+if(!(ructStr.isBlank() || ructStr.isEmpty() || ructStr.equals("NULL") || ructStr.equals("null"))) {
+ruct = Integer.parseInt(ructStr);
+}
+else{
+isValid = false;
+}
+}
+else{
+isValid = false;
+}
+Organ o = this.orgs.findByRuct(ruct);
+if(o == null) {
+errors.append("[WARNING] " + (locale.equals("es") ? "No se ha encontrado el RUCT "+ructStr+", se omiten los registros de esta entrada." : "No s'ha trobat el RUCT "+ructStr+", s'ometen els registres d'aquesta entrada.")).append("<br>").toString();
+continue;
+}
+titulacio = o.getId().getLugar();
+centre = o.getOrgan().getId().getLugar();
+}
+else if(ambit.equals("C")) {
+centre = ambit.equals("T") || ambit.equals("C") ? Integer.parseInt(c.replaceAll("\\D+","")) : null;
+if(centre == null){
+isValid = false;
+}
+}
+
+if(isValid) {
+Integer curs = dstCurs == null ? result.getInt("curs") : dstCurs;
+String tipus = allColNames.contains("tipus") ? result.getString("tipus") : "avg";
+String cursEnquesta = allColNames.contains("curs_enquesta") ? result.getString("curs_enquesta") : null;
+String titulacioOrigen = allColNames.contains("titulacio_origen") ? result.getString("titulacio_origen") : null;
+String centreOrigen = allColNames.contains("centre_origen") ? result.getString("centre_origen") : null;
+Integer nenq = allColNames.contains("nenq") ? result.getInt("nenq") : null;
+String cursd = allColNames.contains("cursd") ? result.getString("cursd") : null;
+for(String colName : colnames) {
+IndicadorEnquestaTmp ie = new IndicadorEnquestaTmp();
+
+ie.setEnquesta(enquesta);
+ie.setTitulacio(titulacio);
+ie.setCentre(centre);
+ie.setCurs(curs);
+ie.setAmbit(ambit); 
+ie.setEstudi(estudi);
+ie.setIndicador(colName.replace("_min", "").replace("_max", "").toLowerCase());
+ie.setNum(null);
+ie.setCursd(cursd);
+ie.setTipus(tipus);
+ie.setUsuari(usuari.getUsuari());
+ie.setData(new Timestamp(System.currentTimeMillis()));
+ie.setCursEnquesta(cursEnquesta);
+ie.setTitulacioOrigen(titulacioOrigen);
+ie.setCentreOrigen(centreOrigen);
+ie.setNenq(nenq);
+ie.setRuct(ruct);
+
+try {
+ie.setValor(result.getString(colName).replace(",", "."));
+}
+catch(Exception ex) {
+ie.setValor(null);
+}
+
+iets.save(ie);
+numRecords++;
+} 
+numTuples++;  
+}
+}
+}
+
+/*  5) Notificar administradores y usuario implicado  */
+this.sendNotificacion(usuari, enquesta, ambit, estudi);
+if(!usuari.isAdmin()){
+this.sendConfirmation(usuari.getUsuari(), enquesta, ambit, estudi);
+}
+errors.append("[INFO] " + (locale.equals("es") ? ("Se han importado "+numRecords.toString()+" nuevos registros para un total de "+numTuples.toString()+" titulaciones") : ("[INFO] S'han importat "+numRecords.toString()+" nous registres per a un total de "+numTuples.toString()+" titulacions")));
+return errors.toString();
+}
+
+public List<String> listTableColumns(Integer dbOrigen, String vista, String locale) throws SQLException, ClassNotFoundException {
+
+Datasource source = this.dss.findById(dbOrigen);
+String query = "SELECT * FROM "+vista+" LIMIT 1;";
+Class.forName(source.getDriver());
+List<String> colNames = new ArrayList<String>();
+try (Connection connection = DriverManager.getConnection(source.getConn())) {
+
+Statement statement = connection.createStatement();
+ResultSet resultset = statement.executeQuery(query);
+
+ResultSetMetaData resultMetadata = resultset.getMetaData();
+int columns = resultMetadata.getColumnCount();
+
+for(int i = 1; i <= columns; i++){
+colNames.add(resultMetadata.getColumnLabel(i));
+}
+
+}
+
+return colNames;
+}
+
+public List<IndicadorEnquestaTmpRepository.IndicadorEnquestaTmpDup> checkDuplicates(String enquesta) {
+return this.iets.checkDuplicates(enquesta);
+}
+
+public Integer consolidateByEnquesta(String enquesta) {
+if(this.iets.checkDuplicates(enquesta).size() > 0) {
+return -1;
+}
+else {
+Integer i = this.ies.consolidateByEnquesta(enquesta);
+this.iets.deleteByEnquesta(enquesta);
+return i;
+}
+}
+
+public Integer countByEnquesta(String enquesta) {
+return this.iets.countByEnquesta(enquesta);
+}
+
+public List<IndicadorEnquestaTmpRepository.IndicadorEnquestaTmpDup> checkIntegrity(String enquesta){
+return this.iets.checkIntegrity(enquesta);
+}
+
+public Integer deleteFromCurrent(String enquesta){
+return this.iets.deleteFromCurrent(enquesta);
+}
+
+public Integer deleteFromPending(String enquesta){
+return this.iets.deleteFromPending(enquesta);
+}
+
+private void setColumnsCod(String ambit, List<String> knownColumns, List<String> mandatoryColumns) {
+knownColumns.addAll(Arrays.asList("ruct", "curs_enquesta", "centre_origen", "titulacio_origen", "nenq", "cursd"));
+if(ambit.equals("U")) {
+mandatoryColumns.addAll(Arrays.asList("curs", "tipus"));
+}
+else if(ambit.equals("C")) {
+mandatoryColumns.addAll(Arrays.asList("curs", "centre", "tipus"));
+}
+else {
+mandatoryColumns.addAll(Arrays.asList("curs", "titulacio", "centre", "tipus"));
+}
+}
+
+private void setColumnsRuct(String ambit, List<String> knownColumns, List<String> mandatoryColumns) {
+knownColumns.addAll(Arrays.asList("curs_enquesta", "centre_origen", "titulacio_origen", "nenq", "cursd"));
+if(ambit.equals("U")) {
+mandatoryColumns.addAll(Arrays.asList("curs", "tipus"));
+}
+else if(ambit.equals("C")) {
+mandatoryColumns.addAll(Arrays.asList("curs", "tipus", "ruct"));
+knownColumns.add("centre");
+}
+else {
+mandatoryColumns.addAll(Arrays.asList("curs", "tipus", "ruct"));
+knownColumns.addAll(Arrays.asList("centre", "titulacio"));
+}
+}
+
+private boolean checkColumns(List<String> header, List<String> mandatoryColumns, StringBuilder errors, String locale) {
+boolean isvalid = true;
+for(String c : mandatoryColumns) {
+if(!header.stream().anyMatch(c::equalsIgnoreCase)) {
+isvalid = false;
+    errors.append((locale.equals("es") ? "[ERROR] No se ha encontrado la columna " : "[ERROR] No s'ha trobat la columna ") +c).append("<br>");
+    }
+}
+return isvalid;
+}
+
+private boolean checkValues(List<CSVRecord> records, String ambit, String clau, StringBuilder errors, String locale) {
+boolean isvalid = true;
+Integer numRecords = 0;
+for (CSVRecord record : records) {
+Map<String, String> recordMap = new LinkedCaseInsensitiveMap<>();
+recordMap.putAll(record.toMap());
+
+String type = recordMap.get("tipus");
+numRecords++;
+
+if((ambit.equals("T") || ambit.equals("C")) && !clau.equals("ruct")) {
+String c = recordMap.get("centre");
+c = translateCentre(c);
+if(!StringUtils.isNumeric(c.replace("C", ""))) {
+isvalid = false;
+errors.append("[ERROR] " + (locale.equals("es") ? "En la linea " : "A la línia ") + numRecords.toString() + ": " + (locale.equals("es") ? c+" no es un valor válido para la columna centre." : c+" no es un valor vàlid per la columna centre.")).append("<br>");
+} 
+}
+
+if(ambit.equals("T")) {
+String t = recordMap.get("titulacio");
+if(!clau.equals("ruct")) {
+t = translateTitulacio(t);
+if(!StringUtils.isNumeric(t)) {
+isvalid = false;
+errors.append("[ERROR] " + (locale.equals("es") ? "En la linea " : "A la línia ") + numRecords.toString() + ": " + (locale.equals("es") ? t+" no es un valor válido para la columna titulacio." : t+" no es un valor vàlid per la columna titulacio.")).append("<br>");
+}
+}
+else {
+String ructStr = recordMap.get("ruct");
+if(!ructStr.isBlank() && ructStr.isEmpty() && ructStr.equals("NULL") && ructStr.equals("null") && !StringUtils.isNumeric(t)) {
+isvalid = false;
+errors.append("[ERROR] " + (locale.equals("es") ? "En la linea " : "A la línia ") + numRecords.toString() + ": " + (locale.equals("es") ? ructStr+" no es un valor válido para la columna ruct." : ructStr+" no es un valor vàlid per la columna ruct.")).append("<br>");
+}
+}
+}
+
+if(!type.equals("avg") && !type.equals("min") && !type.equals("max")) {
+isvalid = false;
+errors.append("[ERROR] " + (locale.equals("es") ? "En la linea " : "A la línia ") + numRecords.toString() + ": " + (locale.equals("es") ? type+" no es un valor válido para la columna tipus." : type+" no es un valor vàlid per la columna tipus.")).append("<br>");
+}
+}
+return isvalid;
+}
+
+private void sendNotificacion(Usuari usuari, String enquesta, String ambit, String estudi) {
+try {
+this.ems.sendMail("saic@uv.es", "[SYS] Datos pendientes de consolidar", "Estimado/a administrador: \n"
++ "\n"
++ "El usuario "+usuari.getUsuari()+" ha importado nuevos datos referentes a: \n"
++ "Origen: "+enquesta+"\n"
++ "Ámbito: "+ambit+"\n"
++ "Tipo titulación: "+estudi+"\n"
++ "\n"
++ "Acceda a https://saic.uv.es y realice las acciones pertinentes para consolidar los datos. ");
+} catch (MessagingException e) {
+e.printStackTrace();
+}
+}
+
+private void sendConfirmation(String to, String enquesta, String ambit, String estudi) {
+try {
+this.ems.sendMail(to, "[SYS] Nuevos datos importados", "Estimado/a usuario: \n"
++ "\n"
++ "Se han importado correctamente nuevos datos referentes a: \n"
++ "Origen: "+enquesta+"\n"
++ "Ámbito: "+ambit+"\n"
++ "Tipo titulación: "+estudi+"\n"
++ "\n"
++ "Los datos se quedarán en estado pendiente de consolidar hasta que un administrador inicie el proceso de consolidación.");
+} catch (MessagingException e) {
+e.printStackTrace();
+}
+}
+
+/* Exepciones en el código de titulación que hay que traducir a código SAIC */
+```
+- `translateTitulacio()` — ⚪ Interno
+```
+/* Exepciones en el código de centro que hay que traducir a código SAIC */
+```
+- `translateCentre()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `DatasourceService`
+**Ubicación:** `src\main\java\es\uv\saic\service\DatasourceService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `DocumentService`
+**Ubicación:** `src\main\java\es\uv\saic\service\DocumentService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getAll()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+- `findAllByCategoriaOrgan()` — ⚪ Interno
+- `findByCategoriaOrgan()` — ⚪ Interno
+- `findByCategoriaNom()` — ⚪ Interno
+- `findByCategoriaTipus()` — ⚪ Interno
+- `archive()` — ⚪ Interno
+- `archiveByOrgan()` — ⚪ Interno
+- `exists()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+- `upload()` — ⚪ Interno
+- `File()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `EmailService`
+**Ubicación:** `src\main\java\es\uv\saic\service\EmailService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `EmailService()` — ⚪ Interno
+- `sendActiveTaskNext()` — ⚪ Interno
+- `addEmail()` — ⚪ Interno
+- `getNextEmail()` — ⚪ Interno
+- `getPendingQueue()` — ⚪ Interno
+- `pendingQueueIsEmpty()` — ⚪ Interno
+- `sendMail()` — ⚪ Interno
+- `SimpleMailMessage()` — ⚪ Interno
+- `sendNewTaskMail()` — ⚪ Interno
+- `Qualitat()` — ⚪ Interno
+```
+//saic.uv.es per a accedir al Sistema d'Assegurament Intern de l
+```
+- `Qualitat()` — ⚪ Interno
+- `Calidad()` — ⚪ Interno
+```
+//saic.uv.es para acceder al Sistema de Aseguramiento Interno de l
+```
+- `Calidad()` — ⚪ Interno
+- `sendCalendarMail()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `EvidenciaIndicadorEnquestaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\EvidenciaIndicadorEnquestaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getIndicadors()` — ⚪ Interno
+- `getByProcesEvidencia()` — ⚪ Interno
+- `getAll()` — ⚪ Interno
+- `removeByProcesEvidencia()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `GraficaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\GraficaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findLikeAmbit()` — ⚪ Interno
+- `findLikeAmbitAndEstudi()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `IndicadorEnquestaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\IndicadorEnquestaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findTypes()` — ⚪ Interno
+- `findByEnquestaCursAmbitEstudi()` — ⚪ Interno
+- `findByEnquestaCursAmbitEstudiCentre()` — ⚪ Interno
+- `findByEnquestaCursAmbitEstudiCentreTitulacio()` — ⚪ Interno
+- `getAssociatedInds()` — ⚪ Interno
+- `getAllInds()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `getAllInds()` — ⚪ Interno
+- `getGraphData()` — ⚪ Interno
+- `getGraphData()` — ⚪ Interno
+- `contains()` — ⚪ Interno
+- `deleteCentroNoAdscrito()` — ⚪ Interno
+- `deleteByEnquesta()` — ⚪ Interno
+- `deleteByEnquestaCurs()` — ⚪ Interno
+- `fixBiennials()` — ⚪ Interno
+- `consolidateByEnquesta()` — ⚪ Interno
+- `deleteAll()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `saveAll()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `IndicadorEnquestaTmpService`
+**Ubicación:** `src\main\java\es\uv\saic\service\IndicadorEnquestaTmpService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findByEnquestaCursAmbitEstudi()` — ⚪ Interno
+- `deleteByEnquesta()` — ⚪ Interno
+- `deleteByEnquestaCursAmbitEstudi()` — ⚪ Interno
+- `checkDuplicates()` — ⚪ Interno
+- `deleteFromCurrent()` — ⚪ Interno
+- `deleteFromPending()` — ⚪ Interno
+- `deleteDuplicates()` — ⚪ Interno
+- `countByEnquesta()` — ⚪ Interno
+- `checkIntegrity()` — ⚪ Interno
+- `deleteAll()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `saveAll()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `IndicadorService`
+**Ubicación:** `src\main\java\es\uv\saic\service\IndicadorService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `IndicadorService()` — ⚪ Interno
+- `getFromTitulacion()` — ⚪ Interno
+- `URL()` — ⚪ Interno
+- `String()` — ⚪ Interno
+- `extract()` — ⚪ Interno
+- `InputSource()` — ⚪ Interno
+```
+// has subin
+```
+- `for()` — ⚪ Interno
+- `Indicador()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `Indicador()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `getGraphData()` — ⚪ Interno
+- `URL()` — ⚪ Interno
+- `String()` — ⚪ Interno
+- `extractAll()` — ⚪ Interno
+- `InputSource()` — ⚪ Interno
+```
+// has subin
+```
+- `for()` — ⚪ Interno
+- `Indicador()` — ⚪ Interno
+- `Indicador()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `InformeService`
+**Ubicación:** `src\main\java\es\uv\saic\service\InformeService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByGrupWeb()` — ⚪ Interno
+- `findByGrupWebTambit()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `InstanciaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\InstanciaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByID()` — ⚪ Interno
+- `getReportFromInstancia()` — ⚪ Interno
+- `filterSupervisables()` — ⚪ Interno
+- `filterSupervisable()` — ⚪ Interno
+- `filterSupervisablesByEvidencies()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `findAll()` — ⚪ Interno
+- `findAllIds()` — ⚪ Interno
+- `findByOrganCursNom()` — ⚪ Interno
+- `findByCentreCursNom()` — ⚪ Interno
+- `findByIdProces()` — ⚪ Interno
+- `findByOrganBetweenCurs()` — ⚪ Interno
+- `exists()` — ⚪ Interno
+- `exists()` — ⚪ Interno
+- `instantiateT()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `instantiateC()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `instantiateU()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `deleteInstance()` — ⚪ Interno
+- `clearInstance()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `InstanciaTascaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\InstanciaTascaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByInstancia()` — ⚪ Interno
+- `findByInstanciaTascap()` — ⚪ Interno
+- `findOlderVersions()` — ⚪ Interno
+- `TascaVersioTransfer()` — ⚪ Interno
+- `findActiveByInstancia()` — ⚪ Interno
+- `findActivesByType()` — ⚪ Interno
+- `isUserAuthorized()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `getReportFromProcesOrgan()` — ⚪ Interno
+- `getReportFromNomProcesOrgan()` — ⚪ Interno
+- `system()` — ⚪ Interno
+- `ProcessBuilder()` — ⚪ Interno
+- `ProcessBuilder()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `ProcessBuilder()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `saveChanges()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `InstanciaTasca()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `findOlderByProces()` — ⚪ Interno
+- `EvidenciaTransfer()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+- `getPastTasks()` — ⚪ Interno
+- `getNext()` — ⚪ Interno
+- `getUsers()` — ⚪ Interno
+- `getLastByProcName()` — ⚪ Interno
+- `deactivateAll()` — ⚪ Interno
+- `remove()` — ⚪ Interno
+- `removeAllVersions()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `InstanciaTascaVerService`
+**Ubicación:** `src\main\java\es\uv\saic\service\InstanciaTascaVerService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findById()` — ⚪ Interno
+- `findByIdInstanciaTasca()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+- `deleteByIdInstancia()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `LinkService`
+**Ubicación:** `src\main\java\es\uv\saic\service\LinkService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findById()` — ⚪ Interno
+- `findByToken()` — ⚪ Interno
+- `findByRuct()` — ⚪ Interno
+- `increase()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `NoticiaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\NoticiaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findVisibles()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `OrganService`
+**Ubicación:** `src\main\java\es\uv\saic\service\OrganService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByID()` — ⚪ Interno
+- `findByRuct()` — ⚪ Interno
+- `exists()` — ⚪ Interno
+- `findAll()` — ⚪ Interno
+- `findCurrentCentres()` — ⚪ Interno
+- `findTitulacionsByCentre()` — ⚪ Interno
+- `getTitulacions()` — ⚪ Interno
+- `getCentres()` — ⚪ Interno
+- `getActiveCentres()` — ⚪ Interno
+- `getTitulacionsByCentre()` — ⚪ Interno
+- `getUsuariTitulacions()` — ⚪ Interno
+- `getUsuariCentres()` — ⚪ Interno
+- `getTitulacionsByCentres()` — ⚪ Interno
+- `getTitulacionsByTypeCentre()` — ⚪ Interno
+- `findActiveTitulacionsByCentreTambit()` — ⚪ Interno
+- `getEquivalents()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `ParserService`
+**Ubicación:** `src\main\java\es\uv\saic\service\ParserService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `ParserService()` — ⚪ Interno
+- `doParse()` — ⚪ Interno
+- `parseOtros()` — ⚪ Interno
+- `parsePas()` — ⚪ Interno
+- `parseEvalProf()` — ⚪ Interno
+- `parseGrauFromUqServer()` — ⚪ Interno
+- `parseMasterFromUqServer()` — ⚪ Interno
+- `parseDoctorado()` — ⚪ Interno
+- `execute()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `IndicadorEnquesta()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `executeRows()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `IndicadorEnquesta()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `translate()` — ⚪ Interno
+- `parseGrauDades1er()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseGrauDades3er()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseGrauDadesGraduats()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseGrauProfes()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseDadesPas()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseMasterData()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+```
+/*+ "AND a.TIT NOT IN(SELECT DISTINCT(TIT) FROM MDB_master.Mitjanes_final_codigeneric) "
++ "UNION "
++ "SELECT 'data' AS enquesta, b.tit AS tit, c.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'T' AS ambit, 'm' AS estudi, "
++ "IT01 AS it01, IT02 AS it02, IT03 AS it03, IT04 AS it04, IT05 AS it05, IT06 AS it06, "
++ "IT07 AS it07, IT08 AS it08, IT09 AS it09, IT10 AS it10, IT11 AS it11, IT12 AS it12, "
++ "IT13 AS it13, IT14 AS it14, IT15 AS it15, IT16 AS it16, IT17 AS it17, IT18 AS it18, "
++ "IT19 AS it19, IT21 AS it21, IT22 AS it22, IT23 AS it23, IT24 AS it24, IT25 AS it25, "
++ "IT26 AS it26, IT27 AS it27, IT28 AS it28, IT29 AS it29, IT30 AS it30, IT30 AS it30, "
++ "IT31 AS it31, IT32 AS it32, IT33 AS it33, G_satis AS g_satis, G_RelQP AS g_relqp, "
++ "G_QProf AS g_qprof, G_Postg AS g_postg, G_Interes AS g_interes, G_Util AS g_util, gcovidm AS gcovid "
++ "FROM MDB_master.Mitjanes_final_codigeneric a "
++ "LEFT JOIN MDB_master.ESTUDIS b ON a.tit = b.tit "
++ "LEFT JOIN MDB_master.Centre c ON b.centre = c.centre "
++ "WHERE Total >= 3 AND CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",*/
+
+"SELECT 'data' AS enquesta, NULL AS tit, b.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "IT01 AS it01, IT02 AS it02, IT03 AS it03, IT04 AS it04, IT05 AS it05, IT06 AS it06, "
++ "IT07 AS it07, IT08 AS it08, IT09 AS it09, IT10 AS it10, IT11 AS it11, IT12 AS it12, IT13 AS it13, "
++ "IT14 AS it14, IT15 AS it15, IT16 AS it16, IT17 AS it17, IT18 AS it18, IT19 AS it19, "
++ "IT21 AS it21, IT22 AS it22, IT23 AS it23, IT24 AS it24, IT25 AS it25, IT26 AS it26, "
++ "IT27 AS it27, IT28 AS it28, IT29 AS it29, IT30 AS it30, IT30 AS it30, IT31 AS it31, "
++ "IT32 AS it32, IT33 AS it33, G_satis AS g_satis, G_RelQP AS g_relqp, G_QProf AS g_qprof, "
++ "G_Postg AS g_postg, G_Interes AS g_interes, G_Util AS g_util "
++ "FROM MDB_master.Mitjanes_final_xcentre a "
++ "LEFT JOIN MDB_master.Centre b ON a.centre = b.centre WHERE CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",
+
+"SELECT 'data' AS enquesta, NULL AS tit, NULL AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'U' AS ambit, 'm' AS estudi, "
++ "IT01 AS it01, IT02 AS it02, IT03 AS it03, IT04 AS it04, IT05 AS it05, IT06 AS it06, "
++ "IT07 AS it07, IT08 AS it08, IT09 AS it09, IT10 AS it10, IT11 AS it11, IT12 AS it12, IT13 AS it13, "
++ "IT14 AS it14, IT15 AS it15, IT16 AS it16, IT17 AS it17, IT18 AS it18, IT19 AS it19, "
++ "IT21 AS it21, IT22 AS it22, IT23 AS it23, IT24 AS it24, IT25 AS it25, IT26 AS it26, "
++ "IT27 AS it27, IT28 AS it28, IT29 AS it29, IT30 AS it30, IT30 AS it30, IT31 AS it31, "
++ "IT32 AS it32, IT33 AS it33, G_satis AS g_satis, G_RelQP AS g_relqp, G_QProf AS g_qprof, "
++ "G_Postg AS g_postg, G_Interes AS g_interes, G_Util AS g_util "
++ "FROM MDB_master.Mitjanes_final_global "
++ "WHERE CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",
+
+"SELECT 'data' AS enquesta, NULL AS tit, b.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "max_it13m AS it13_max, min_it13m AS it13_min, max_it14m AS it14_max, min_it14m AS it14_min, "
++ "max_it15m AS it15_max, min_it15m AS it15_min, max_it16m AS it16_max, min_it16m AS it16_min, "
++ "max_it17m AS it17_max, min_it17m AS it17_min "
++ "FROM MDB_master.MinMax_final_xcentre a "
++ "LEFT JOIN MDB_master.Centre b ON a.centre = b.centre WHERE CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";"};
+
+return this.execute(statement, queries);
+}
+
+private int parseMasterDataG(Connection connection, String year) throws SQLException {
+
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'data_g' AS enquesta, b.tit AS tit, c.cmostrar AS centre, CONCAT('20', RIGHT(cursf, 2)) AS curs, null AS cursd, 'T' AS ambit, 'm' AS estudi, "
++ "IT01m_pf AS it01_pf, IT02m_pf AS it02_pf, IT03m_pf AS it03_pf, IT04m_comp AS it04_comp, "
++ "IT04m_comp AS it05_comp, IT06m_comp AS it06_comp, IT07m_comp AS it07_comp, "
++ "IT08m_comp AS it08_comp, IT09m_comp AS it09_comp, IT10m_comp AS it10_comp, "
++ "IT11m_de AS it11_de, IT12m_de AS it12_de, IT13m_de AS it13_de, IT14m_de AS it14_de, "
++ "IT15m_de AS it15_de, IT16m_de AS it16_de, (IT17_pe_S/(IT17_pe_S+IT17_pe_N))*100 AS it17_pe, "
++ "IT18m_pe AS it18_pe, IT19m_pe AS it19_pe, IT20m_pe AS it20_pe, IT21m_pe AS it21_pe, "
++ "IT22m_pe AS it22_pe, IT23m_pe AS it23_pe, (IT24_mob_S/(IT24_mob_S+IT24_mob_N))*100 AS it24_mob, "
++ "IT25_mob1 AS it25_mob1, IT25_mob2 AS it25_mob2, IT25_mob3 AS it25_mob3, IT25_mob4 AS it25_mob4, "
++ "IT26m_mob AS it26_mob, IT27m_mob AS it27_mob, IT28m_mob AS it28_mob, IT29m_mob AS it29_mob, "
++ "IT30m_mob AS it30_mob, IT26m_mob AS it26_mob, IT31m_mob AS it31_mob, IT32m_mob AS it32_mob, "
++ "IT33m_mob AS it33_mob, IT34m_tfm AS it34_tfm, IT35m_tfm AS it35_tfm, IT36m_tfm AS it36_tfm, "
++ "IT37m_tfm AS it37_tfm, IT38m_tfm AS it38_tfm, IT40m_treb AS it40_treb, IT41m_treb AS it41_treb, "
++ "IT41m_treb AS it41_treb, IT42m_treb AS it42_treb, IT43m_treb AS it43_treb, gm_Qprof AS g_qprof, "
++ "gm_instal AS g_instal, gm_exp AS g_exp, gm_recomana AS g_recomana "
++ "FROM MDB_master.Mitjanes_Gxtitcursf a "
++ "LEFT JOIN MDB_master.ESTUDIS b ON a.tit = b.tit "
++ "LEFT JOIN MDB_master.Centre c ON b.centre = c.centre WHERE CONCAT('20', RIGHT(cursf, 2)) >= "+year+";",
+
+"SELECT 'data_g' AS enquesta, NULL AS tit, b.cmostrar AS centre, CONCAT('20', RIGHT(cursf, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "IT01m_pf AS it01_pf, IT02m_pf AS it02_pf, IT03m_pf AS it03_pf, IT04m_comp AS it04_comp, "
++ "IT04m_comp AS it05_comp, IT06m_comp AS it06_comp, IT07m_comp AS it07_comp, "
++ "IT08m_comp AS it08_comp, IT09m_comp AS it09_comp, IT10m_comp AS it10_comp, "
++ "IT11m_de AS it11_de, IT12m_de AS it12_de, IT13m_de AS it13_de, IT14m_de AS it14_de, "
++ "IT15m_de AS it15_de, IT16m_de AS it16_de, (IT17_pe_S/(IT17_pe_S+IT17_pe_N))*100 AS it17_pe, "
++ "IT18m_pe AS it18_pe, IT19m_pe AS it19_pe, IT20m_pe AS it20_pe, IT21m_pe AS it21_pe, "
++ "IT22m_pe AS it22_pe, IT23m_pe AS it23_pe, (IT24_mob_S/(IT24_mob_S+IT24_mob_N))*100 AS it24_mob, "
++ "IT25_mob1 AS it25_mob1, IT25_mob2 AS it25_mob2, IT25_mob3 AS it25_mob3, IT25_mob4 AS it25_mob4, "
++ "IT26m_mob AS it26_mob, IT27m_mob AS it27_mob, IT28m_mob AS it28_mob, IT29m_mob AS it29_mob, "
++ "IT30m_mob AS it30_mob, IT26m_mob AS it26_mob, IT31m_mob AS it31_mob, IT32m_mob AS it32_mob, "
++ "IT33m_mob AS it33_mob, IT34m_tfm AS it34_tfm, IT35m_tfm AS it35_tfm, IT36m_tfm AS it36_tfm, "
++ "IT37m_tfm AS it37_tfm, IT38m_tfm AS it38_tfm, IT40m_treb AS it40_treb, IT41m_treb AS it41_treb, "
++ "IT41m_treb AS it41_treb, IT42m_treb AS it42_treb, IT43m_treb AS it43_treb, gm_Qprof AS g_qprof, "
++ "gm_instal AS g_instal, gm_exp AS g_exp, gm_recomana AS g_recomana "
++ "FROM MDB_master.Mitjanes_Gxcentrecursf a "
++ "LEFT JOIN MDB_master.Centre b ON a.centre = b.centre WHERE CONCAT('20', RIGHT(cursf, 2)) >= "+year+";",
+
+"SELECT 'data_g' AS enquesta, NULL AS tit, NULL AS centre, CONCAT('20', RIGHT(cursf, 2)) AS curs, null AS cursd, 'U' AS ambit, 'm' AS estudi, "
++ "IT01m_pf AS it01_pf, IT02m_pf AS it02_pf, IT03m_pf AS it03_pf, IT04m_comp AS it04_comp, "
++ "IT04m_comp AS it05_comp, IT06m_comp AS it06_comp, IT07m_comp AS it07_comp, "
++ "IT08m_comp AS it08_comp, IT09m_comp AS it09_comp, IT10m_comp AS it10_comp, "
++ "IT11m_de AS it11_de, IT12m_de AS it12_de, IT13m_de AS it13_de, IT14m_de AS it14_de, "
++ "IT15m_de AS it15_de, IT16m_de AS it16_de, (IT17_pe_S/(IT17_pe_S+IT17_pe_N))*100 AS it17_pe, "
++ "IT18m_pe AS it18_pe, IT19m_pe AS it19_pe, IT20m_pe AS it20_pe, IT21m_pe AS it21_pe, "
++ "IT22m_pe AS it22_pe, IT23m_pe AS it23_pe, (IT24_mob_S/(IT24_mob_S+IT24_mob_N))*100 AS it24_mob, "
++ "IT25_mob1 AS it25_mob1, IT25_mob2 AS it25_mob2, IT25_mob3 AS it25_mob3, IT25_mob4 AS it25_mob4, "
++ "IT26m_mob AS it26_mob, IT27m_mob AS it27_mob, IT28m_mob AS it28_mob, IT29m_mob AS it29_mob, "
++ "IT30m_mob AS it30_mob, IT26m_mob AS it26_mob, IT31m_mob AS it31_mob, IT32m_mob AS it32_mob, "
++ "IT33m_mob AS it33_mob, IT34m_tfm AS it34_tfm, IT35m_tfm AS it35_tfm, IT36m_tfm AS it36_tfm, "
++ "IT37m_tfm AS it37_tfm, IT38m_tfm AS it38_tfm, IT40m_treb AS it40_treb, IT41m_treb AS it41_treb, "
++ "IT41m_treb AS it41_treb, IT42m_treb AS it42_treb, IT43m_treb AS it43_treb, gm_Qprof AS g_qprof, "
++ "gm_instal AS g_instal, gm_exp AS g_exp, gm_recomana AS g_recomana "
++ "FROM MDB_master.Mitjanes_Gxcursf WHERE CONCAT('20', RIGHT(cursf, 2)) >= "+year+";",
+
+"SELECT 'data_g' AS enquesta, NULL AS tit, b.cmostrar AS centre, CONCAT('20', RIGHT(cursf, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "max_IT26m_mob AS it26_mob_max, min_IT26m_mob AS it26_mob_min, "
++ "max_IT27m_mob AS it27_mob_max, min_IT27m_mob AS it27_mob_min, "
++ "max_IT28m_mob AS it28_mob_max, min_IT28m_mob AS it28_mob_min, "
++ "max_IT29m_mob AS it29_mob_max, min_IT29m_mob AS it29_mob_min, "
++ "max_IT30m_mob AS it30_mob_max, min_IT30m_mob AS it30_mob_min, "
++ "max_IT31m_mob AS it31_mob_max, min_IT31m_mob AS it31_mob_min, "
++ "max_IT32m_mob AS it32_mob_max, min_IT32m_mob AS it32_mob_min, "
++ "max_IT33m_mob AS it33_mob_max, min_IT33m_mob AS it33_mob_min, "
++ "max_gm_instal AS g_instal_max, min_gm_instal AS g_instal_min "
++ "FROM MDB_master.MinMax_Gxcursfcentre a "
++ "LEFT JOIN MDB_master.Centre b ON a.centre = b.centre WHERE CONCAT('20', RIGHT(cursf, 2)) >= "+year+";"
+};
+
+return this.execute(statement, queries);
+}
+
+private int parseMasterProfes(Connection connection, String year) throws SQLException {
+
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'profes_tancades' AS enquesta, b.tit AS tit, c.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'T' AS ambit, 'm' AS estudi, "
++ "A1 AS a1, A2 AS a2, A3 AS a3, A4 AS a4, A5 AS a5, A6 AS a6, A7 AS a7, A8 AS a8, A9 AS a9, A10 AS a10, "
++ "A11 AS a11, A12 as a12, A13 AS a13, A14 AS a14, A15_1 AS a15_1, A15_2 AS a15_2, A15_3 AS a15_3, "
++ "A15_4 AS a15_4, A15_5 AS a15_5, A16 AS a16, A17 AS a17, A18 AS a18, A19 AS a19, A20 AS a20, "
++ "A21 AS a21, A26 AS a26, A27 AS a27, A28 AS a28, A29 AS a29, A30 AS a30, A31 AS a31, A32 AS a32 "
++ "FROM MDB_master.Mitjanes_profesXtit a "
++ "LEFT JOIN MDB_master.ESTUDIS b ON a.tit = b.tit "
++ "LEFT JOIN MDB_master.Centre c ON b.centre = c.centre WHERE CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",
+
+"SELECT 'profes_tancades' AS enquesta, NULL AS tit, c.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "A1 AS a1, A2 AS a2, A3 AS a3, A4 AS a4, A5 AS a5, A6 AS a6, A7 AS a7, A8 AS a8, A9 AS a9, A10 AS a10, "
++ "A11 AS a11, A12 as a12, A13 AS a13, A14 AS a14, A15_1 AS a15_1, A15_2 AS a15_2, A15_3 AS a15_3, "
++ "A15_4 AS a15_4, A15_5 AS a15_5, A16 AS a16, A17 AS a17, A18 AS a18, A19 AS a19, A20 AS a20, "
++ "A21 AS a21, A26 AS a26, A27 AS a27, A28 AS a28, A29 AS a29, A30 AS a30, A31 AS a31, A32 AS a32 "
++ "FROM MDB_master.Mitjanes_profesxCurscentre a "
++ "LEFT JOIN MDB_master.periodesCurs p ON p.curs = CONCAT('20', RIGHT(ACURS, 2)) "
++ "LEFT JOIN MDB_master.Centre c ON a.centre = c.centre WHERE p.ProfesComplet = 1 AND CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",
+
+"SELECT 'profes_tancades' AS enquesta, NULL AS tit, NULL AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'U' AS ambit, 'm' AS estudi,"
++ "A1 AS a1, A2 AS a2, A3 AS a3, A4 AS a4, A5 AS a5, A6 AS a6, A7 AS a7, A8 AS a8, A9 AS a9, A10 AS a10, "
++ "A11 AS a11, A12 as a12, A13 AS a13, A14 AS a14, A15_1 AS a15_1, A15_2 AS a15_2, A15_3 AS a15_3, "
++ "A15_4 AS a15_4, A15_5 AS a15_5, A16 AS a16, A17 AS a17, A18 AS a18, A19 AS a19, A20 AS a20, "
++ "A21 AS a21, A26 AS a26, A27 AS a27, A28 AS a28, A29 AS a29, A30 AS a30, A31 AS a31, A32 AS a32 "
++ "FROM MDB_master.Mitjanes_profesxCurs a"
++ "LEFT JOIN MDB_master.periodesCurs p ON p.curs = CONCAT('20', RIGHT(ACURS, 2)) "
++ "WHERE p.ProfesComplet = 1 AND CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";",
+
+"SELECT 'profes_tancades' AS enquesta, NULL AS tit, c.cmostrar AS centre, CONCAT('20', RIGHT(ACURS, 2)) AS curs, null AS cursd, 'C' AS ambit, 'm' AS estudi, "
++ "max_A16m AS a16_max, min_A16m AS a16_min, max_A17m AS a17_max, min_A17m AS a17_min, "
++ "max_A19m AS a19_max, min_A19m AS a19_min "
++ "FROM MDB_master.MinMax_profesxCurscentre a "
++ "LEFT JOIN MDB_master.periodesCurs p ON p.curs = CONCAT('20', RIGHT(ACURS, 2)) "
++ "LEFT JOIN MDB_master.Centre c ON a.centre = c.centre WHERE p.ProfesComplet = 1 AND CONCAT('20', RIGHT(ACURS, 2)) >= "+year+";"};
+
+return this.execute(statement, queries);
+}
+
+
+private int parseEvalProfBD(Connection connection, String year) throws SQLException {
+ 
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'evalprof' AS enquesta, t.cod_titula AS tit, c.cod_actual AS centre, CONCAT('20', anyo) AS curs, null AS cursd, 'T' AS ambit, tipus AS estudi, "
++ "it01, it02, it03, it04, it05, it06, it07, it08, it09, it10, it11, it12, it13, it14, b1, b2, b3, b4, b5, b6, global "
++ "FROM MDB_evalProf.MediasTitulacion m "
++ "LEFT JOIN MDB_evalProf.Titulaciones t ON m.estudio = t.estudio "
++ "LEFT JOIN MDB_evalProf.Centros c ON t.cod_centro = c.cod_centro "
++ "WHERE c.cod_actual IS NOT NULL AND c.cod_actual <> '' AND num_encues >= 3 AND CONCAT('20', anyo) >= "+year+"; ",
+
+"SELECT 'evalprof' AS enquesta, NULL AS tit, c.cod_actual AS centre, CONCAT('20', anyo) AS curs, null AS cursd, 'C' AS ambit, tipus AS estudi, "
++ "it01, it02, it03, it04, it05, it06, it07, it08, it09, it10, it11, it12, it13, it14, b1, b2, b3, b4, b5, b6, global "
++ "FROM MDB_evalProf.MediasCentro m "
++ "LEFT JOIN MDB_evalProf.Centros c ON m.centre = c.cod_centro "
++ "LEFT JOIN MDB_master.periodesCurs p ON p.curs = CONCAT('20', anyo) "
++ "WHERE c.cod_actual IS NOT NULL AND c.cod_actual <> '' AND CONCAT('20', anyo) >= "+year+"; ",
+
+"SELECT 'evalprof' AS enquesta, NULL AS tit, NULL AS centre, CONCAT('20', anyo) AS curs, null AS cursd, 'U' AS ambit, tipus AS estudi, "
++ "it01, it02, it03, it04, it05, it06, it07, it08, it09, it10, it11, it12, it13, it14, b1, b2, b3, b4, b5, b6, global "
++ "FROM MDB_evalProf.MediasUniversidad "
++ "LEFT JOIN MDB_master.periodesCurs p ON p.curs = CONCAT('20', anyo) "
++ "WHERE CONCAT('20', anyo) >= "+year+"; "};
+
+return this.execute(statement, queries);
+
+}
+
+private int parseOtrosProfes(Connection connection) throws SQLException {
+ 
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'otros' AS enquesta, t.cod_titula AS tit, c.cod_actual AS centre, curs, null AS cursd, ambit, estudi, "
++ "I_RH2_06, I_RH2_07, I_RH2_08, I_RH2_profcursos, I_RH2_totpdi "
++ "FROM MDB_otros.profesorado m "
++ "LEFT JOIN MDB_evalProf.Titulaciones t ON m.titulacion = t.estudio "
++ "LEFT JOIN MDB_evalProf.Centros c ON t.cod_centro = c.cod_centro "
++ "WHERE c.cod_actual IS NOT NULL AND c.cod_actual <> '';"};
+
+return this.execute(statement, queries);
+
+}
+
+private int parseOtrosEncuestas(Connection connection) throws SQLException {
+ 
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'enquestes' AS enquesta, titulacio AS tit, centre, curs, null AS cursd, ambit, estudi, "
++ "1er_modul_cod, 1er_modul_nom, 1er_modul_obs, 3er_modul_cod, 3er_modul_nom, 3er_modul_obs "
++ "FROM MDB_otros.asignaturas_encuestas;"};
+
+return this.execute(statement, queries);
+
+}
+
+private int parseOtrosTasas(Connection connection) throws SQLException {
+ 
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT 'otros' AS enquesta, t.cod_titula AS tit, c.cod_actual AS centre, curs, null AS cursd, ambit, estudi, "
++ "i_oe1_nb_nuevos, i_oe1_nb_plazas, i_oe1_tasa_mat, i_oe1_tasa_ofedem "
++ "FROM MDB_otros.tasas m "
++ "LEFT JOIN MDB_evalProf.Titulaciones t ON m.titulacion = t.estudio "
++ "LEFT JOIN MDB_evalProf.Centros c ON t.cod_centro = c.cod_centro "
++ "WHERE c.cod_actual IS NOT NULL AND c.cod_actual <> '';"};
+
+return this.execute(statement, queries);
+
+}
+
+private int parseOtrosDocentia(Connection connection) throws SQLException {
+ 
+Statement statement = connection.createStatement();
+String[] queries = {
+"SELECT *  "
++ "FROM MDB_otros.docentia_evaluacion "
++ "WHERE centre IS NOT NULL;"};
+
+return this.execute(statement, queries);
+
+}
+
+/* ToDo */
+```
+- `parseDocEstud()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseDocEtesi()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseDocProf()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `CONCAT()` — ⚪ Interno
+- `parseDocTasas()` — ⚪ Interno
+- `parseDocInds()` — ⚪ Interno
+- `parseDocRecom()` — ⚪ Interno
+- `LOWER()` — ⚪ Interno
+- `doAction()` — ⚪ Interno
+- `precargaEvalProf()` — ⚪ Interno
+- `CAST()` — ⚪ Interno
+- `CAST()` — ⚪ Interno
+- `CAST()` — ⚪ Interno
+- `precargaMaster()` — ⚪ Interno
+- `precargaDoctorado()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `PlantillaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\PlantillaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `DecimalFormat()` — ⚪ Interno
+- `findAll()` — ⚪ Interno
+- `findByID()` — ⚪ Interno
+- `findByVersioCodiAmbit()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+- `isUsed()` — ⚪ Interno
+- `addTemplateData()` — ⚪ Interno
+- `data()` — ⚪ Interno
+- `addTemplateData()` — ⚪ Interno
+- `data()` — ⚪ Interno
+- `addHeaderData()` — ⚪ Interno
+- `ClassPathResource()` — ⚪ Interno
+- `ClassPathResource()` — ⚪ Interno
+- `iterateLoopAttr()` — ⚪ Interno
+- `iterateLoopTag()` — ⚪ Interno
+- `replaceValues()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `Element()` — ⚪ Interno
+- `getTemplateData()` — ⚪ Interno
+- `replaceValuesLoop()` — ⚪ Interno
+- `formatValue()` — ⚪ Interno
+- `savePDF()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `PrintWriter()` — ⚪ Interno
+- `ProcessBuilder()` — ⚪ Interno
+- `toPDF()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `PrintWriter()` — ⚪ Interno
+- `ProcessBuilder()` — ⚪ Interno
+- `parseComments()` — ⚪ Interno
+- `String()` — ⚪ Interno
+- `ObjectMapper()` — ⚪ Interno
+- `replaceSection()` — ⚪ Interno
+- `extractTemplateAnchor()` — ⚪ Interno
+- `clear()` — ⚪ Interno
+- `asString()` — ⚪ Interno
+- `InputStreamReader()` — ⚪ Interno
+- `UncheckedIOException()` — ⚪ Interno
+- `readFileToString()` — ⚪ Interno
+- `DefaultResourceLoader()` — ⚪ Interno
+- `asString()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `ProcesService`
+**Ubicación:** `src\main\java\es\uv\saic\service\ProcesService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByID()` — ⚪ Interno
+- `findByName()` — ⚪ Interno
+- `findByNameCurs()` — ⚪ Interno
+- `getAll()` — ⚪ Interno
+- `getSupervisableCursos()` — ⚪ Interno
+- `getSupervisableProcedures()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `deleteById()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+- `getFlowDiagram()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `RolService`
+**Ubicación:** `src\main\java\es\uv\saic\service\RolService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findOne()` — ⚪ Interno
+- `findAssignables()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `SysStatusService`
+**Ubicación:** `src\main\java\es\uv\saic\service\SysStatusService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findByType()` — ⚪ Interno
+- `log()` — ⚪ Interno
+- `SysStatus()` — ⚪ Interno
+- `Timestamp()` — ⚪ Interno
+- `err()` — ⚪ Interno
+- `SysStatus()` — ⚪ Interno
+- `Timestamp()` — ⚪ Interno
+- `warn()` — ⚪ Interno
+- `SysStatus()` — ⚪ Interno
+- `Timestamp()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `TascaService`
+**Ubicación:** `src\main\java\es\uv\saic\service\TascaService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findByProces()` — ⚪ Interno
+- `getByID()` — ⚪ Interno
+- `getByProcesTascap()` — ⚪ Interno
+- `getAllEvidencies()` — ⚪ Interno
+- `getEvidenciesByCentreTitulacioCurs()` — ⚪ Interno
+- `getEvidencesByProcedure()` — ⚪ Interno
+- `getAllAvailableEvidences()` — ⚪ Interno
+- `create()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `deleteById()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `TipusService`
+**Ubicación:** `src\main\java\es\uv\saic\service\TipusService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findOne()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `UsuariService`
+**Ubicación:** `src\main\java\es\uv\saic\service\UsuariService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `findByUsername()` — ⚪ Interno
+- `hasActiveRol()` — ⚪ Interno
+- `getActiveInstanciaTasques()` — ⚪ Interno
+- `getActiveInstancies()` — ⚪ Interno
+- `getSupervisableProcessos()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// Role
+```
+- `especiales()` — ⚪ Interno
+- `getSupervisableCentres()` — ⚪ Interno
+- `getInstanceAsignedUsers()` — ⚪ Interno
+- `findByRolCentre()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `UsuarisRolService`
+**Ubicación:** `src\main\java\es\uv\saic\service\UsuarisRolService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findAll()` — ⚪ Interno
+- `exists()` — ⚪ Interno
+- `find()` — ⚪ Interno
+- `findActive()` — ⚪ Interno
+- `findLast()` — ⚪ Interno
+- `findLastNum()` — ⚪ Interno
+- `hasActiveRol()` — ⚪ Interno
+- `findActiveRols()` — ⚪ Interno
+- `isGrantedUser()` — ⚪ Interno
+- `isGrantedSupervisor()` — ⚪ Interno
+- `isAdminUser()` — ⚪ Interno
+- `isDataTestUser()` — ⚪ Interno
+- `hasActiveRol()` — ⚪ Interno
+- `hasActiveRoles()` — ⚪ Interno
+- `hasActiveAmbit()` — ⚪ Interno
+- `hasAssociatedProcs()` — ⚪ Interno
+- `findAssociatedProcs()` — ⚪ Interno
+- `findManagerByCentre()` — ⚪ Interno
+- `findManagerByTitulacio()` — ⚪ Interno
+- `findManagerByCentres()` — ⚪ Interno
+- `findManagerByTitulacions()` — ⚪ Interno
+- `getSpecialRoles()` — ⚪ Interno
+- `save()` — ⚪ Interno
+- `delete()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `WikiService`
+**Ubicación:** `src\main\java\es\uv\saic\service\WikiService.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `findByCategoria()` — ⚪ Interno
+- `save()` — ⚪ Interno
+
+---
+
+
+# 📈 Estadísticas finales
+
+- Total de clases: 30
+- Total de métodos: 438
+- Total de comentarios: 8
+
+✅ **Fin del reporte de carpeta.**

+ 1650 - 0
reporte_web.md

@@ -0,0 +1,1650 @@
+# 📁 Reporte de carpeta: `web`
+
+> Detalle de clases, métodos y comentarios extraídos automáticamente
+
+
+### 🧩 Clase: `AdminController`
+**Ubicación:** `src\main\java\es\uv\saic\web\AdminController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+// GET para conseguir todas las instancias del sistema en ese momento.
+```
+- `getInstances()` — 🟢 Endpoint
+```
+// Función utilizada para conseguir las instancias que tiene todo el sistema
+```
+- `loadInstanceData()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que recoge los campos introducidos en los inputs (Proceso, centro y titulación) y busca las instancias relacionadas
+```
+- `instantiate()` — 🟢 Endpoint
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// Type T procedure for one whole categor
+```
+- `place()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// Type C procedure for all active place
+```
+- `for()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+```
+// GET que recoge todos los procedimientos del sistema
+```
+- `getProcedures()` — 🟢 Endpoint
+```
+// Función utilizada en el GET que recoge todos los procedimientos
+```
+- `loadProceduresData()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que elimina una instancia concreta
+```
+- `deleteInstance()` — 🟢 Endpoint
+```
+// POST que reinicia una instancia por completo
+```
+- `clearInstance()` — 🟢 Endpoint
+- `Email()` — ⚪ Interno
+```
+// POST que establece que una instancia ha sido cerrada, cambiandole su estado
+```
+- `closeInstance()` — 🟢 Endpoint
+```
+// POST que se encarga de eliminar una tarea concreta de una instancia
+```
+- `removeTask()` — 🟢 Endpoint
+```
+// POST que se encarga de reiniciar por completo una tarea de una instancia
+```
+- `clearTask()` — 🟢 Endpoint
+```
+// POST que reinicia una tarea del procedimiento, eliminando datos anteriores y creando una nueva vesión de esta
+```
+- `reloadTask()` — 🟢 Endpoint
+- `InstanciaTasca()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+```
+// POST que tiene como objetivo reactivar una tarea
+```
+- `activateTask()` — 🟢 Endpoint
+- `InstanciaTasca()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+```
+// POST que edita la información de una tarea ya existente
+```
+- `editTask()` — 🟢 Endpoint
+- `InstanciaTasca()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `getMailing()` — 🟢 Endpoint
+- `sendMails()` — 🟢 Endpoint
+- `Email()` — ⚪ Interno
+```
+// POST para la creación de un procedimiento nuevo
+```
+- `newProcedure()` — 🟢 Endpoint
+- `Proces()` — ⚪ Interno
+- `Tasca()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+```
+// POST para editar un procedimiento ya existente
+```
+- `editProcedure()` — 🟢 Endpoint
+- `Tasca()` — ⚪ Interno
+- `Tasca()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+```
+// POST que elimina un procedimiento
+```
+- `removeProcedure()` — 🟢 Endpoint
+```
+// POST que le eliminar un usuario concreto del sitema
+```
+- `removeUserrole()` — 🟢 Endpoint
+```
+// POST para añadir un nuevo usuario al sistema
+```
+- `newUserrole()` — 🟢 Endpoint
+- `Usuari()` — ⚪ Interno
+- `UsuarisRol()` — ⚪ Interno
+- `UsuarisRol()` — ⚪ Interno
+- `UsuarisRol()` — ⚪ Interno
+- `UsuarisRol()` — ⚪ Interno
+- `getTemplates()` — 🟢 Endpoint
+```
+// GET que recoge todas las plantillas actuales del sistema
+```
+- `getTemplates2()` — 🟢 Endpoint
+- `File()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `File()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `loadTemplateData()` — ⚪ Interno
+```
+// POST que redefine que indicadores están asociados a una evidencia dentro de un proceso
+```
+- `updateTemplateInds()` — 🟢 Endpoint
+- `EvidenciaIndicadorEnquesta()` — ⚪ Interno
+- `EvidenciaIndicadorEnquestaPK()` — ⚪ Interno
+```
+// GET para abrir el editor de plantillas
+```
+- `getTemplateEditor()` — 🟢 Endpoint
+- `testTemplateEditor()` — 🟢 Endpoint
+```
+// GET para la carga del calendario
+```
+- `calendar()` — 🟢 Endpoint
+- `acreditacionsByCurs()` — 🟢 Endpoint
+- `AcreditacioTransfer()` — ⚪ Interno
+- `AcreditacioTransfer()` — ⚪ Interno
+- `AcreditacioTransfer()` — ⚪ Interno
+- `UpdateAcreditacio()` — 🟢 Endpoint
+- `SimpleDateFormat()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `AjaxController`
+**Ubicación:** `src\main\java\es\uv\saic\web\AjaxController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `getActiveCentres()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `getActiveTitulationsByCenter()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que buscar titulaciones que se encuentren asociadas a uno o varios centros
+```
+- `getTitulationsByCenter()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que se utiliza para conseguir los cursos a partir de la titulación
+```
+- `getYearsByCenterTitulation()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que se utiliza para conseguir los procedimiento que se han llevado a cabo por cursos y por titulación
+```
+- `getProceduresByCenterTitulationYear()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST para buscar pas evidencias a partir del año, centro y titulación
+```
+- `getEvidencesByCenterTitulationYear()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST que recoge toda las titulaciones que contiene un centro para el manager
+```
+- `getCenterTitulations()` — 🟢 Endpoint
+- `getTitulationsByCenters()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `getTitulationsByCenter()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `getAllTitulationsByCenter()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST para encontrar el centro a partir de los procedimientos
+```
+- `getAllCentresByAmbit()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+// POST para encontrar un procedimiento concreto
+```
+- `findProcedure()` — 🟢 Endpoint
+- `Proces()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// POST para encontar las plantillas concretas para cierta titulación, centro o procedimiento
+```
+- `findTemplates()` — 🟢 Endpoint
+- `findTemplatesInds()` — 🟢 Endpoint
+```
+// GET para renderizar el formulario de cración de nueva tarea
+```
+- `newTaskForm()` — 🟢 Endpoint
+- `newUserRoleForm()` — 🟢 Endpoint
+- `findTemplate()` — 🟢 Endpoint
+```
+// GET para comprobar si una plantilla esta siendo usada
+```
+- `isTemplateUsed()` — 🟢 Endpoint
+```
+// POST para crear el form de creación de plantilla
+```
+- `formTemplate()` — 🟢 Endpoint
+- `Plantilla()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// DELETE para eliminar una plantilla concreta
+```
+- `formTemplateRemove()` — 🟢 Endpoint
+```
+// POST para guadar una de las plantillas
+```
+- `templateSave()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+- `Plantilla()` — ⚪ Interno
+- `saveTemplate()` — 🟢 Endpoint
+```
+// POST para añadir un evento al calendario
+```
+- `calendarAddEvent()` — 🟢 Endpoint
+- `SimpleDateFormat()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `Calendari()` — ⚪ Interno
+```
+// POST que actualiza el evento ddel calendario
+```
+- `calendarAddEvent()` — 🟢 Endpoint
+- `SimpleDateFormat()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+```
+// GET que recoge todos los eventos del calendario
+```
+- `calendarGetEvents()` — 🟢 Endpoint
+```
+// DELETE que elimina un evento del calendario
+```
+- `calendarDeleteEvent()` — 🟢 Endpoint
+```
+// POST para instanciar un proceso desde el calendario
+```
+- `instantiate()` — 🟢 Endpoint
+- `BigInteger()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `BigInteger()` — ⚪ Interno
+- `Email()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `groupedTitToText()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `DashboardController`
+**Ubicación:** `src\main\java\es\uv\saic\web\DashboardController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+// GET para cargar el dashboard con toda su información
+```
+- `getOrganList()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+//GET para mostrar el dashboard a partir de un numero ruct
+```
+- `getDashboardOrgan()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `loadReports()` — ⚪ Interno
+- `AnyDimensioDTO()` — ⚪ Interno
+- `TreeDTOAny()` — ⚪ Interno
+- `TreeDTOOrgan()` — ⚪ Interno
+- `TreeDTOInstancia()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+- `TreeDTOOrgan()` — ⚪ Interno
+- `TreeDTOInstancia()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `TreeDTODimensio()` — ⚪ Interno
+- `InstanciaDTO()` — ⚪ Interno
+- `DimensioInstanciesDTO()` — ⚪ Interno
+```
+// GET para conseguir la documentación ya a aportada a partir del id de la tituación
+```
+- `loadDocuments()` — 🟢 Endpoint
+- `CategoriaDocumentDTO()` — ⚪ Interno
+- `DocumentDTO()` — ⚪ Interno
+- `DocumentDTO()` — ⚪ Interno
+- `loadGantt()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+- `getDocumentChildCats()` — 🟢 Endpoint
+- `getDocumentChildCatsU()` — 🟢 Endpoint
+```
+// POST para guardar un documento en el sistema
+```
+- `uploadDocument()` — 🟢 Endpoint
+- `Document()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+```
+// POST para añadir un documento a un centro cocncreto
+```
+- `archiveDocuments()` — 🟢 Endpoint
+```
+// GET para conseguir todos los graficos a partir de un RUCT
+```
+- `getGraphDataList()` — 🟢 Endpoint
+```
+//GET para conseguir todos los datos concretos de tasas para las tablas
+```
+- `getGraphDataTaxes()` — 🟢 Endpoint
+```
+//GET para conseguir todos los datos concretos de cada gráfico
+```
+- `getGraphData()` — 🟢 Endpoint
+- `Indicador()` — ⚪ Interno
+- `CursoValor()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `CursoValor()` — ⚪ Interno
+- `Indicador()` — ⚪ Interno
+- `CursoValor()` — ⚪ Interno
+- `getLinks()` — 🟢 Endpoint
+- `createLink()` — 🟢 Endpoint
+- `SimpleDateFormat()` — ⚪ Interno
+- `Link()` — ⚪ Interno
+- `Date()` — ⚪ Interno
+- `deleteLink()` — 🟢 Endpoint
+```
+// Función encargada de cargar a los managers a partir del centro y titulación
+```
+- `loadManagers()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+```
+// Función para comprobar si un usario esta permitido para hacer una acción
+```
+- `isSuitable()` — ⚪ Interno
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// Función para saber el tamaño de un documento concreto
+```
+- `getSize()` — ⚪ Interno
+- `FileSystemResource()` — ⚪ Interno
+- `bytesToHuman()` — ⚪ Interno
+- `StringCharacterIterator()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `DataController`
+**Ubicación:** `src\main\java\es\uv\saic\web\DataController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+// GET que carga la interfaz relacionada con toda la importación de datos
+```
+- `renderImport()` — 🟢 Endpoint
+```
+// POST encargado de importar los datos que han sido adjuntados
+```
+- `uploadFile()` — 🟢 Endpoint
+- `InputStreamReader()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// POST encargado de eliminar unos datos concretos
+```
+- `delete()` — 🟢 Endpoint
+```
+// POST encargado de mostrar los datos por pantalla
+```
+- `show()` — 🟢 Endpoint
+```
+// GET para mostrar el formulario de busqueda de datos
+```
+- `current()` — 🟢 Endpoint
+```
+//GET para cargar el apartado de coonsolidate
+```
+- `consolidate()` — 🟢 Endpoint
+- `check()` — ⚪ Interno
+```
+// POST que soluciona problemas de integridad que puedan tener los datos
+```
+- `fixIntegrityIssues()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+```
+// POST que soluciona problemas de duplicados que puedan tener los datos
+```
+- `fixDuplicatesIssues()` — 🟢 Endpoint
+```
+// POST que consolida los datos pasadas por la encuesta
+```
+- `consolidate()` — 🟢 Endpoint
+```
+// POST que comprueba los datos a partir de la encuesta
+```
+- `countByEnquesta()` — 🟢 Endpoint
+```
+// POST para mostrar los datos en columnas
+```
+- `listTableColumns()` — 🟢 Endpoint
+```
+// GET que muestra los datos de un curso que se ha elegido
+```
+- `show()` — 🟢 Endpoint
+```
+// POST que muestra los datos del curso actual
+```
+- `currentShow()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+- `getDatasources()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `DownloadController`
+**Ubicación:** `src\main\java\es\uv\saic\web\DownloadController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Download a file associated with a task instance
+ * @param model
+ * @param idInstanciaTasca The ID of the task instance
+ * @param response HttpServletResponse
+ * @return A FileSystemResource representing the file to download
+ */
+```
+- `download()` — 🟢 Endpoint
+- `FileSystemResource()` — ⚪ Interno
+- `FileSystemResource()` — ⚪ Interno
+- `FileNotFoundException()` — ⚪ Interno
+```
+/*
+ * Download a document by its ID
+ * @param model
+ * @param idDocument The ID of the document to download
+ * @param response HttpServletResponse
+ * @return A FileSystemResource representing the document to download
+ */
+```
+- `downloadDocument()` — 🟢 Endpoint
+- `FileSystemResource()` — ⚪ Interno
+- `FileNotFoundException()` — ⚪ Interno
+```
+/*
+ * Download the latest report for a given process and degree
+ * @param model
+ * @param idTitulacio The ID of the degree
+ * @param nomProces The name of the process
+ * @param response HttpServletResponse
+ * @return A FileSystemResource representing the report to download
+ */
+```
+- `downloadReport()` — 🟢 Endpoint
+- `File()` — ⚪ Interno
+- `FileSystemResource()` — ⚪ Interno
+- `FileSystemResource()` — ⚪ Interno
+```
+/*
+ * Download a populated template for a given task instance
+ * @param model
+ * @param idTascai The ID of the task instance
+ * @param response HttpServletResponse
+ * @return A byte array representing the populated template to download
+ */
+```
+- `downloadTemplate()` — 🟢 Endpoint
+```
+/* Check if specific template exists */
+Integer idTitulacio = it.getInstancia().getTitulacio();
+String templatePath = this.templatePath+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+if(it.getInstancia().getOrgan().getTambit().equals("G") | idTitulacio == 1) {
+File f = new File(this.templatePath+"/T1/"+tasca.getCodiEvidencia().replace(".", "_")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T1/"+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+}
+}
+else if(it.getInstancia().getOrgan().getTambit().equals("M") | idTitulacio == 2) {
+File f = new File(this.templatePath+"/T2/"+tasca.getCodiEvidencia().replace(".", "_")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T2/"+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+}
+}
+
+File f = new File(templatePath);
+if(!f.exists()) {
+FileNotFoundException e = new FileNotFoundException("No se ha encontrado la plantilla "+tasca.getCodiEvidencia()+".docx");
+e.setStackTrace(new StackTraceElement[0]);
+throw e;
+}
+
+InputStream in = new FileInputStream(f);
+IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, reportId, TemplateEngineKind.Velocity);
+FieldsMetadata metadata = new FieldsMetadata();
+metadata.addFieldAsImage("logo");
+report.setFieldsMetadata(metadata);
+IContext context = report.createContext();
+IImageProvider img;
+if(new File(this.logoPath+"C"+Integer.toString(it.getInstancia().getCentre())+".png").exists()) {
+img = new FileImageProvider(new File(this.logoPath+"C"+Integer.toString(it.getInstancia().getCentre())+".png"));
+}
+else {
+img = new FileImageProvider(new File(this.logoPath+"C0.png"));
+}
+context.put("logo", img);
+context.put("centre", it.getInstancia().getOrgan().getOrgan().getNomVal());
+context.put("titulacio", it.getInstancia().getOrgan().getNomCas());
+context.put("curs", Integer.toString(it.getInstancia().getProces().getCursAvaluat()-1)+" - "+Integer.toString(it.getInstancia().getProces().getCursAvaluat()));
+context.put("curs_anterior", Integer.toString(it.getInstancia().getProces().getCursAvaluat()-2)+" - "+Integer.toString(it.getInstancia().getProces().getCursAvaluat()-1));
+
+Proces proces = it.getInstancia().getProces();
+Integer idCentre = it.getInstancia().getCentre();
+
+if(tasca.getTipus().getTipus() == 14) { // Iterable template task
+List<Organ> titulacions = new ArrayList<Organ>();
+Integer ambit = idTitulacio/(int)1000;
+titulacions = os.getTitulacionsByTypeCentre(it.getInstancia().getOrgan().getOrgan().getId().getLugar(), ambit);
+List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
+for(Organ x : titulacions) {
+HashMap<String, String> t = getTemplateDataArray(x.getId().getLugar(), idCentre, proces.getCursAvaluat());
+t.put("titulacio", x.getNomCas());
+data.add(t);
+} 
+context.put("data", data);
+getTemplateData(idTitulacio, idCentre, proces.getCursAvaluat(), context);
+}
+else { // NO iterable template task
+getTemplateData(idTitulacio, idCentre, proces.getCursAvaluat(), context);
+}
+
+ByteArrayOutputStream out = new ByteArrayOutputStream();  
+report.process(context, out);
+    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+tasca.getCodiEvidencia()+".docx\"");
+
+return out.toByteArray();
+
+}
+
+/*
+ * Populate the template data into the context
+ * @param idTitulacio The ID of the degree
+ * @param idCentre The ID of the center
+ * @param curs The academic year
+ * @param context The IContext to populate
+ */
+```
+- `getTemplateData()` — ⚪ Interno
+```
+/*  Indicadores del data warehouse */
+try {
+List<Indicador> indicadores;
+indicadores = this.is.getFromTitulacion(idTitulacio.toString(), curs);
+for(Indicador i : indicadores) { 
+context.put(i.getIndicador(), i.getValor());
+}
+} 
+catch(Exception e) { }
+
+/*  Indicadores de encuestas  */
+List<IndicadorEnquestaRepository.IndicadorEnquestaValor> enquestesT;
+enquestesT = this.ies.getAllInds(idTitulacio, idCentre, curs);
+
+for(IndicadorEnquestaRepository.IndicadorEnquestaValor i : enquestesT) {
+String indicador = i.getAmbit().equals("t") ? (i.getEnquesta()+"_"+i.getIndicador()) : (i.getEnquesta()+"_"+i.getIndicador()+"_"+i.getAmbit());
+indicador = i.getTipus().equals("avg") ? indicador : (indicador += "_"+i.getTipus());
+indicador = i.getCursd() == null ? indicador : (indicador += "_"+i.getCursd());
+context.put(indicador, formatValue(i.getValor()));
+}
+}
+
+/*
+ * Format a value for template insertion
+ * @param v The value to format
+ * @return The formatted value
+ */
+```
+- `formatValue()` — ⚪ Interno
+```
+/*
+ * Get template data as a HashMap
+ * @param idTitulacio The ID of the degree
+ * @param idCentre The ID of the center
+ * @param curs The academic year
+ * @return A HashMap containing the template data
+ */
+private HashMap<String, String> getTemplateDataArray(Integer idTitulacio, Integer idCentre, Integer curs) {
+
+HashMap<String, String> info = new HashMap<String, String>();
+
+/*  Indicadores del data warehouse */
+try {
+List<Indicador> indicadores;
+indicadores = this.is.getFromTitulacion(idTitulacio.toString(), curs);
+for(Indicador i : indicadores) { 
+info.put(i.getIndicador(), i.getValor());
+}
+} 
+catch(Exception e) { }
+
+/*  Indicadores de encuestas  */
+List<IndicadorEnquestaRepository.IndicadorEnquestaValor> enquestesT;
+enquestesT = this.ies.getAllInds(idTitulacio, idCentre, curs);
+
+for(IndicadorEnquestaRepository.IndicadorEnquestaValor i : enquestesT) {
+String indicador = i.getAmbit().equals("t") ? (i.getEnquesta()+"_"+i.getIndicador()) : (i.getEnquesta()+"_"+i.getIndicador()+"_"+i.getAmbit());
+indicador = i.getTipus().equals("avg") ? indicador : (indicador += "_"+i.getTipus());
+indicador = i.getCursd() == null ? indicador : (indicador += "_"+i.getCursd());
+info.put(indicador, formatValue(i.getValor()));
+}
+
+return info;
+}
+
+/*
+ * Test endpoint to generate a populated template for a given task (id of task)
+ * @param model
+ * @param idTitulacio The ID of the degree
+ * @param idCentre The ID of the center
+ * @param idTascap The ID of the task
+ * @param idProces The ID of the process
+ * @param response HttpServletResponse
+ * @return A byte array representing the populated template
+ */
+```
+- `testTemplate()` — 🟢 Endpoint
+```
+/* Check if specific template exists */
+String templatePath = this.templatePath+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+if(titulacio.getTambit().equals("G") | idTitulacio == 1) {
+File f = new File(this.templatePath+"/T1/"+tasca.getCodiEvidencia().replace(".", "_")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T1/"+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+}
+}
+else if(titulacio.getTambit().equals("M") | idTitulacio == 2) {
+File f = new File(this.templatePath+"/T2/"+tasca.getCodiEvidencia().replace(".", "_")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T2/"+tasca.getCodiEvidencia().replace(".", "_")+".docx";
+}
+}
+
+InputStream in = new FileInputStream(new File(templatePath));
+IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, reportId, TemplateEngineKind.Velocity);
+FieldsMetadata metadata = new FieldsMetadata();
+metadata.addFieldAsImage("logo");
+report.setFieldsMetadata(metadata);
+IContext context = report.createContext();
+IImageProvider img;
+if(new File(this.logoPath+"C"+Integer.toString(idCentre)+".png").exists()) {
+img = new FileImageProvider(new File(this.logoPath+"C"+Integer.toString(idCentre)+".png"));
+}
+else {
+img = new FileImageProvider(new File(this.logoPath+"C0.png"));
+}
+context.put("logo", img);
+context.put("centre", centre.getNomVal());
+context.put("titulacio", titulacio.getNomVal());
+context.put("curs", Integer.toString(proces.getCursAvaluat()-1)+" - "+Integer.toString(proces.getCursAvaluat()));
+context.put("curs_anterior", Integer.toString(proces.getCursAvaluat()-2)+" - "+Integer.toString(proces.getCursAvaluat()-1));
+
+if(tasca.getTipus().getTipus() == 14) { // Iterable template task
+List<Organ> titulacions = new ArrayList<Organ>();
+titulacions = os.getTitulacionsByTypeCentre(centre.getId().getLugar(), ambit);
+List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
+for(Organ x : titulacions) {
+HashMap<String, String> t = getTemplateDataArray(x.getId().getLugar(), idCentre, proces.getCursAvaluat());
+t.put("titulacio", x.getNomCas());
+data.add(t);
+}
+context.put("data", data);
+getTemplateData(idTitulacio, idCentre, proces.getCursAvaluat(), context);
+}
+else { // NO iterable template task
+getTemplateData(idTitulacio, idCentre, proces.getCursAvaluat(), context);
+}
+
+ByteArrayOutputStream out = new ByteArrayOutputStream();  
+report.process(context, out);
+    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+tasca.getCodiEvidencia()+".docx\"");
+
+return out.toByteArray();
+
+}
+
+/*
+ * Test endpoint to generate a populated template for a given degree and evidence (Type of task)
+ * @param model
+ * @param idTitulacio The ID of the degree
+ * @param idCentre The ID of the center
+ * @param evidencia The name of the evidence
+ * @param curs The academic year
+ * @param tipusTasca The type of task
+ * @param response HttpServletResponse
+ * @return A byte array representing the populated template
+ */
+```
+- `testTemplate()` — 🟢 Endpoint
+```
+/* Check if specific template exists */
+String templatePath = this.templatePath+evidencia.replace(".", "_").replace(" (G)", "").replace(" (M)", "")+".docx";
+if(idTitulacio < 2000 | idTitulacio == 1) {
+File f = new File(this.templatePath+"/T1/"+evidencia.replace(".", "_").replace(" (G)", "").replace(" (M)", "")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T1/"+evidencia.replace(".", "_").replace(" (G)", "").replace(" (M)", "")+".docx";
+}
+ambit = 1;
+}
+else if((idTitulacio >= 2000 & idTitulacio < 3000) | idTitulacio == 2) {
+File f = new File(this.templatePath+"/T2/"+evidencia.replace(".", "_").replace(" (G)", "").replace(" (M)", "")+".docx");
+if(f.exists() && !f.isDirectory()) { 
+templatePath = this.templatePath+"/T2/"+evidencia.replace(".", "_").replace(" (G)", "").replace(" (M)", "")+".docx";
+}
+ambit = 2;
+}
+
+InputStream in = new FileInputStream(new File(templatePath));
+IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, reportId, TemplateEngineKind.Velocity);
+FieldsMetadata metadata = new FieldsMetadata();
+metadata.addFieldAsImage("logo");
+report.setFieldsMetadata(metadata);
+IContext context = report.createContext();
+IImageProvider img;
+if(new File(this.logoPath+"C"+Integer.toString(idCentre)+".png").exists()) {
+img = new FileImageProvider(new File(this.logoPath+"C"+Integer.toString(idCentre)+".png"));
+}
+else {
+img = new FileImageProvider(new File(this.logoPath+"C0.png"));
+}
+context.put("logo", img);
+context.put("centre", centre.getNomVal());
+context.put("titulacio", titulacio.getNomVal());
+context.put("curs", Integer.toString(curs-1)+" - "+Integer.toString(curs));
+context.put("curs_anterior", Integer.toString(curs-2)+" - "+Integer.toString(curs-1));
+
+if(tipusTasca == 14) { // Iterable template task
+List<Organ> titulacions = new ArrayList<Organ>();
+titulacions = os.getTitulacionsByTypeCentre(centre.getId().getLugar(), ambit);
+List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
+for(Organ x : titulacions) {
+HashMap<String, String> t = getTemplateDataArray(x.getId().getLugar(), idCentre, curs);
+t.put("titulacio", x.getNomCas());
+data.add(t);
+}
+context.put("data", data);
+getTemplateData(idTitulacio, idCentre, curs, context);
+}
+else { // NO iterable template task
+getTemplateData(idTitulacio, idCentre, curs, context);
+}
+
+ByteArrayOutputStream out = new ByteArrayOutputStream();  
+report.process(context, out);
+    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+evidencia+".docx\"");
+
+return out.toByteArray();
+
+}
+
+/*
+ * Generate a PDF from the content of a task instance (unused)
+ * @param model
+ * @param idTascai The ID of the task instance
+ * @param response HttpServletResponse
+ * @return A byte array representing the generated PDF
+ */
+```
+- `downloadTemplatePdf()` — 🟢 Endpoint
+```
+/*
+ * Generate a PDF preview from provided content
+ * @param model
+ * @param content The content to convert to PDF
+ * @param idtascai Optional ID of the task instance for context
+ * @param response HttpServletResponse
+ */
+```
+- `downloadTemplatePdf()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `ExportController`
+**Ubicación:** `src\main\java\es\uv\saic\web\ExportController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Export data for a given process and task as CSV
+ * @param model
+ * @param auth Authentication
+ * @param response HttpServletResponse
+ * @param id_p Process ID
+ * @param id_t Task ID
+ */
+```
+- `exportData()` — 🟢 Endpoint
+```
+//@GetMapping("/export/{id_p}/{id_t}")  
+//public void exportData(Model model, Authentication auth, HttpServletResponse response, 
+//@PathVariable Integer id_p, @PathVariable Integer id_t) throws IOException {
+//if(!((Usuari)auth.getPrincipal()).isAdmin() & !((Usuari)auth.getPrincipal()).isDataTest()) {
+//return;
+//}
+//
+//response.setContentType("text/csv");
+//        response.setCharacterEncoding("UTF-8");
+//        response.setHeader("Content-Disposition", "attachment; filename=data_export.csv");
+//
+//PrintWriter pw = response.getWriter();
+//Proces p = this.ps.findByID(id_p);
+//List<Instancia> ins = p.getInstancies();
+//List<String[]> lines = new ArrayList<>();
+//if(p.getNomProces().equals("SAEM")) {
+//String[] header = {"centre", "titulacio", "cod_int", "nom_int", "per_int", "obs_int", "cod_fin", "nom_fin", "per_fin", "obs_fin", "data_fi_docencia"};
+//lines.add(header);
+//}
+//else {
+//String[] header = {"centre", "titulacio", "cod_assignatura_1er", "nom_assignatura_1er", "obs_assignatura_1er", "cod_assignatura_3er", "nom_assignatura_3er", "obs_assignatura_3er"};
+//lines.add(header);
+//}
+//
+//for(Instancia i : ins) {
+//InstanciaTasca it = i.getInstanciaTasca().stream()
+//     .filter(c -> id_t.equals(c.getTasca().getIdTascap()))
+//     .findAny()
+//     .orElse(null);
+//if(it == null) {
+//continue;
+//}
+//if(!it.getEstat().equals("E")){
+//continue;
+//}
+//
+//System.out.println(it.getText());
+//Document doc = Jsoup.parseBodyFragment(it.getText());
+//        int size = lines.get(0).length;
+//        String[] line = new String[size];
+//        line[0] = i.getCentre().toString();
+//line[1] = i.getTitulacio().toString();
+//String[] ids = {"", "",
+////"ind_enquestes_1er_modul_cod", "ind_enquestes_1er_modul_nom", "ind_enquestes_1er_modul_per", "ind_enquestes_1er_modul_obs", 
+//        //"ind_enquestes_3er_modul_cod", "ind_enquestes_3er_modul_nom", "ind_enquestes_3er_modul_per", "ind_enquestes_3er_modul_obs", 
+//    "ind_enquestes_1er_modul_cod", "ind_enquestes_1er_modul_nom", "ind_enquestes_1er_modul_obs", 
+//        "ind_enquestes_3er_modul_cod", "ind_enquestes_3er_modul_nom", "ind_enquestes_3er_modul_obs", 
+//        "mceEditable"};
+//
+//for(int x = 2; x<=8; x++) {
+//if(ids[x].startsWith("ind_")) {
+//try {
+//if(ids[x].equals("ind_enquestes_1er_modul_obs")) {
+//line[x] = doc.getElementById("ind_enquestes_1er_modul_nom").nextElementSibling().text();
+//}
+//else {
+//System.out.println(doc.getElementById(ids[x]));
+//line[x] = doc.getElementById(ids[x]).text();
+//}
+//
+//}
+//catch(Exception e) {
+//line[x] = "[error]";
+//System.out.println("instancia: "+i.getIdInstancia().toString()+", centre: "+i.getCentre().toString()+", titulacio: "+i.getTitulacio().toString());
+//}
+//}/*
+//else {
+//try {
+//line[x] = doc.getElementsByClass(ids[x]).last().text();
+//}
+//catch(Exception e) {
+//line[x] = "[error]";
+//System.out.println("instancia: "+i.getIdInstancia().toString()+", centre: "+i.getCentre().toString()+", titulacio: "+i.getTitulacio().toString());
+//}
+//}*/
+//}
+//
+//lines.add(line);    
+//}
+//
+//lines.stream()
+//         .map(this::convertToCSV)
+//         .forEach(pw::println);
+//pw.close();
+//pw.flush();
+//}
+
+/*
+ * Export data for a given process and task as CSV (not used)
+ * @param model
+ * @param auth Authentication
+ * @param response HttpServletResponse
+ * @param id_p Process ID
+ * @param id_t Task ID
+ */
+```
+- `exportData2()` — 🟢 Endpoint
+```
+/*
+ * Convert an array of Strings to a single CSV line, escaping special characters
+ * @param data Array of Strings to convert
+ * @return A single CSV line as a String
+ */
+```
+- `convertToCSV()` — ⚪ Interno
+```
+/*
+ * Escape special characters in a String for CSV format
+ * @param data The String to escape
+ * @return The escaped String
+ */
+```
+- `escapeSpecialCharacters()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `IndexController`
+**Ubicación:** `src\main\java\es\uv\saic\web\IndexController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Redirect root to /procedures if authenticated, to /login otherwise
+ * @param model
+ * @param auth Authentication
+ * @return "procedures" if authenticated, "redirect: login" otherwise
+ */
+```
+- `getHome()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `KeepAliveController`
+**Ubicación:** `src\main\java\es\uv\saic\web\KeepAliveController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Simple endpoint to check if the user session is still active.
+ * Returns "alive" if the user
+ * is authenticated, "0" otherwise.
+ * @param model
+ * @param auth Authentication
+ * @return "alive" if the user is
+ * authenticated, "0" otherwise.
+ */
+```
+- `getItems()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `LoginController`
+**Ubicación:** `src\main\java\es\uv\saic\web\LoginController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `get()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `ManagersController`
+**Ubicación:** `src\main\java\es\uv\saic\web\ManagersController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Load the managers administration page data into the model
+ * - List of centres and titulacions the logged user can manage
+ * - List of all users
+ * - List of assignable roles
+ * - If there are search results in the session, load them too
+ * - If there is a roleExists attribute in the session, load it too
+ * - The view is managers.html
+ */
+```
+- `managersForm()` — 🟢 Endpoint
+```
+/*
+ * Process the search form submission and load the results into the model
+ * @Param centres List of centre ids to search managers in
+ * @Param titulacions List of titulacion ids to search managers in
+ * @Return The view component list_managers
+ */
+```
+- `managersSearch()` — 🟢 Endpoint
+```
+/*
+ * Load the search results into the model
+ * @Param model The model to load the data into
+ * @Param centres List of centre ids to search managers in
+ * @Param titulacions List of titulacion ids to search managers in
+ */
+```
+- `loadManagers()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+- `compare()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `ParseController`
+**Ubicación:** `src\main\java\es\uv\saic\web\ParseController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Load the parsing options page data into the model
+ * @param model
+ * @param auth Authentication
+ * @param err Optional error message
+ * @param ok Optional success message
+ * @return The name of the view to render
+ */
+```
+- `getParse()` — 🟢 Endpoint
+- `if()` — ⚪ Interno
+```
+/*
+ * Parse a given table from a given database for a given year
+ * @param model
+ * @param auth Authentication
+ * @param response HttpServletResponse
+ * @param database The database to parse from
+ * @param table The table to parse from
+ * @param year The year to parse from
+ */
+```
+- `doParse()` — 🟢 Endpoint
+```
+/*
+ * Parse table depending on the action requested: mediasCentroNP, bienalesProfesGrado, etc
+ * @param model
+ * @param auth Authentication
+ * @param response HttpServletResponse
+ * @param action The action to perform
+ */
+```
+- `doAction()` — 🟢 Endpoint
+```
+/*
+ * Method to delete survey indicators from the database
+ * @param model
+ * @param auth Authentication
+ * @param response HttpServletResponse
+ * @param action The survey to delete indicators from
+ * @param year The year of the survey to delete indicators from (0 for all years)
+ */
+```
+- `doDelete()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `ProceduresController`
+**Ubicación:** `src\main\java\es\uv\saic\web\ProceduresController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/* Redirect root to /procedures */
+```
+- `getRoot()` — 🟢 Endpoint
+```
+/*
+ * Load the list of active procedure instances for the logged-in user
+ * 
+ * @param model 
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param _new Optional parameter to indicate a new access
+ * @return The name of the view to render
+ */
+```
+- `getActiveInstances()` — 🟢 Endpoint
+- `InstanciaTransfer()` — ⚪ Interno
+```
+/*
+ * Loads a procedure instance and its tasks
+ * 
+ * @param model 
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id Instancia ID Instance to load
+ * @return The name of the view to render
+ */
+```
+- `getInstance()` — 🟢 Endpoint
+```
+/*
+ * Updates a task instance with evidence files (for specific task types)
+ * 
+ * @param model
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id Instancia ID Instance to load
+ * @param params Form parameters
+ * @param evidencias List of evidence files (if any)
+ * @return The number of files uploaded (as a String)
+ * @throws IllegalStateException
+ * @throws IOException
+ * @throws InterruptedException
+ */
+```
+- `updateInstanciaTascaEvidencia()` — 🟢 Endpoint
+- `BigInteger()` — ⚪ Interno
+```
+/* Tipos de tarea permitidas */
+final Set<Integer> suitable = Set.of(1, 12, 14);
+
+boolean newTask = (suitable.contains(it.getTasca().getTipus().getTipus())) && it.getEstat().equals("E") && 
+   (((Usuari)auth.getPrincipal()).isAdmin() || ((Usuari)auth.getPrincipal()).isGranted());
+
+if(suitable.contains(it.getTasca().getTipus().getTipus())) {   // Evidencia iterable
+String fileName = "";
+
+if(evidencias.size() > 1) {
+fileName = (newTask ? it.getIdInstanciaTasca().add(new BigInteger("1")).toString() : it.getIdInstanciaTasca().toString()) + ".zip";
+try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(filePath+fileName))) {
+    for(MultipartFile f : evidencias) {
+    File tempFile = File.createTempFile("saic", "temp");
+    tempFile.deleteOnExit();
+    f.transferTo(tempFile);
+        zipOut.putNextEntry(new ZipEntry(f.getOriginalFilename()));
+        Files.copy(Paths.get(tempFile.getAbsolutePath()), zipOut);
+    }
+}
+}
+else if(evidencias.size() == 1){
+MultipartFile evidencia = evidencias.get(0);
+fileName = (newTask ? it.getIdInstanciaTasca().add(new BigInteger("1")).toString() : it.getIdInstanciaTasca().toString()) + "." +
+FilenameUtils.getExtension(evidencia.getOriginalFilename());
+evidencia.transferTo(new File(filePath+fileName));
+}
+else {
+return "0";
+}
+
+if(newTask){
+InstanciaTasca itNew = new InstanciaTasca();
+itNew.setUsuari((Usuari)auth.getPrincipal());
+itNew.setDataFet(new Date(System.currentTimeMillis()));
+itNew.setData(new Date(System.currentTimeMillis()));
+itNew.setEstat("E");
+itNew.setEvidencia(fileName);
+itNew.setInstancia(it.getInstancia());
+itNew.setTasca(it.getTasca());
+itNew.setVersion(it.getVersion()+1);
+itNew.setIdInstanciaTasca(it.getIdInstanciaTasca().add(new BigInteger("1")));
+its.save(itNew);
+}
+else {
+it.setEvidencia(fileName);
+it.setEstat("E");
+this.saveChanges(model, auth, session, it);
+}
+}
+
+return Integer.toString(evidencias.size()); 
+}
+
+/*
+ * Updates a task instance
+ * 
+ * @param model 
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id Instancia ID Instance to load
+ * @param params Form parameters
+ * @param evidencias List of evidence files (if any)
+ * @return The name of the view to render
+ */
+```
+- `updateInstanciaTasca()` — 🟢 Endpoint
+- `BigInteger()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+// SI/N
+```
+- `if()` — ⚪ Interno
+- `if()` — ⚪ Interno
+```
+/*
+ * Saves changes to a task instance
+ * 
+ * @param model 
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param it InstanciaTasca to save
+ */
+```
+- `saveChanges()` — ⚪ Interno
+```
+/*
+ * Saves a draft of a task instance (for specific task types)
+ * 
+ * @param model
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id Instancia ID Instance to load
+ * @param text Text content of the draft
+ * @param manual Whether the save was manually triggered by the user
+ * @return The timestamp of the save operation formatted as a String
+ */
+```
+- `saveDraft()` — 🟢 Endpoint
+- `Date()` — ⚪ Interno
+- `InstanciaTascaVer()` — ⚪ Interno
+- `Timestamp()` — ⚪ Interno
+```
+/*
+ * Loads a procedure instance and its tasks into the model
+ * @param model
+ * @param auth Authentication
+ * @param id Instancia ID Instance to load
+ * @return The name of the view to render
+ */
+```
+- `loadProcedure()` — ⚪ Interno
+- `InstanciaTransfer()` — ⚪ Interno
+- `InstanciaTascaTransfer()` — ⚪ Interno
+```
+/* Comprobar estado evidencia, si vacío inyectar contenido de plantilla asociada */
+if(it.getText() == null && active) {
+itt.setText(pls.addTemplateData(it, p.getText()));
+}
+else if(active){
+itt.setText(it.getText());
+}
+}
+else {
+itt.setCodiEvidencia(it.getTasca().getCodiEvidencia());
+itt.setNomEvidenciaCas(it.getTasca().getNomEvidenciaCas());
+itt.setNomEvidenciaVal(it.getTasca().getNomEvidenciaVal());
+itt.setEvidencia(it.getEvidencia());
+}
+
+if(it.getUsuari() != null) {
+itt.setUsuariFet(it.getUsuari().getNom() + " " + it.getUsuari().getCognoms());
+}
+else {
+itt.setUsuariFet("");
+}
+itt.setAssignedToUser(its.isUserAuthorized(((Usuari)auth.getPrincipal()), itt.getIdInstanciaTasca()));
+itt.setOldEvidences(its.findOlderByProces(it.getInstancia().getCentre(), it.getInstancia().getTitulacio(), it.getInstancia().getProces().getNomProces(), i.getProces().getCursActivacio(), this.pls));
+itt.setVersions(its.findOlderVersions(it.getInstancia().getIdInstancia(), it.getTasca().getIdTasca(), it.getVersion(), this.pls));
+tasks.add(itt);
+}
+model.addAttribute("tasks", tasks);
+model.addAttribute("flow", this.getFlowDiagram(i.getProces()));
+}
+
+/*
+ * Get all drafts for a given task instance
+ * @param model
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id InstanciaTasca ID to load drafts for
+ * @return The name of the view to render
+ */
+```
+- `getDrafts()` — 🟢 Endpoint
+```
+/*
+ * Get a specific draft for a given task instance
+ * @param model
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id InstanciaTasca ID to load drafts for
+ * @param dataMod Timestamp of the draft to load
+ * @return The InstanciaTascaVer object representing the draft
+ */
+```
+- `getDraft()` — 🟢 Endpoint
+```
+/*
+ * Restore a specific draft for a given task instance
+ * @param model
+ * @param auth Authentication
+ * @param session HttpSession
+ * @param id InstanciaTasca ID to restore draft for
+ * @param dataMod Timestamp of the draft to restore
+ * @return "1" if successful, "0" otherwise
+ */
+```
+- `restoreDraft()` — 🟢 Endpoint
+```
+/*
+ * Generate a flow diagram for a given process
+ * @param proces The process to generate the flow diagram for
+ * @return A String containing the flow diagram
+ */
+```
+- `getFlowDiagram()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `ActiveSession`
+**Ubicación:** `src\main\java\es\uv\saic\web\StatsController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `setId()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setNpi()` — ⚪ Interno
+- `setExpired()` — ⚪ Interno
+- `setLastRequest()` — ⚪ Interno
+- `getId()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getNpi()` — ⚪ Interno
+- `getExpired()` — ⚪ Interno
+- `getLastRequest()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setEmail()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getEmail()` — ⚪ Interno
+```
+/*
+ * Renders the admin stats page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @return The name of the view to render
+ */
+```
+- `getStats()` — 🟢 Endpoint
+- `ActiveSession()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `PendingEmail()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `PendingEmail`
+**Ubicación:** `src\main\java\es\uv\saic\web\StatsController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `setId()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setNpi()` — ⚪ Interno
+- `setExpired()` — ⚪ Interno
+- `setLastRequest()` — ⚪ Interno
+- `getId()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getNpi()` — ⚪ Interno
+- `getExpired()` — ⚪ Interno
+- `getLastRequest()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setEmail()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getEmail()` — ⚪ Interno
+```
+/*
+ * Renders the admin stats page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @return The name of the view to render
+ */
+```
+- `getStats()` — 🟢 Endpoint
+- `ActiveSession()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `PendingEmail()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `StatsController`
+**Ubicación:** `src\main\java\es\uv\saic\web\StatsController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+- `setId()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setNpi()` — ⚪ Interno
+- `setExpired()` — ⚪ Interno
+- `setLastRequest()` — ⚪ Interno
+- `getId()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getNpi()` — ⚪ Interno
+- `getExpired()` — ⚪ Interno
+- `getLastRequest()` — ⚪ Interno
+- `setUsername()` — ⚪ Interno
+- `setFullName()` — ⚪ Interno
+- `setEmail()` — ⚪ Interno
+- `getUsername()` — ⚪ Interno
+- `getFullName()` — ⚪ Interno
+- `getEmail()` — ⚪ Interno
+```
+/*
+ * Renders the admin stats page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @return The name of the view to render
+ */
+```
+- `getStats()` — 🟢 Endpoint
+- `ActiveSession()` — ⚪ Interno
+- `SimpleDateFormat()` — ⚪ Interno
+- `PendingEmail()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `SupervisionController`
+**Ubicación:** `src\main\java\es\uv\saic\web\SupervisionController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Renders the supervision page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param session The HTTP session
+ * @return The name of the view to render
+ */
+```
+- `supervisionForm()` — 🟢 Endpoint
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+- `DummyDataTransfer()` — ⚪ Interno
+```
+/*
+ * Handles the supervision search form submission
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param centres The selected centers
+ * @param cursos The selected years
+ * @param titulacions The selected titulacions
+ * @param procediments The selected procedures
+ * @param evidencies The selected evidences
+ * @param searchType The type of search (by procedures or evidences)
+ * @param session The HTTP session
+ * @return The name of the view to render
+ */
+```
+- `supervisionSearch()` — 🟢 Endpoint
+- `SupervisionSearchParams()` — ⚪ Interno
+```
+/*
+ * Restores the previous search results from the session
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param session The HTTP session
+ * @return The name of the view to render
+ */
+```
+- `restoreSearch()` — 🟢 Endpoint
+```
+/*
+ * Loads the search results based on the provided filters
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param centres The selected centers
+ * @param titulacions The selected titulacions
+ * @param cursos The selected years
+ * @param procediments The selected procedures
+ * @param evidencies The selected evidences
+ * @param searchType The type of search (by procedures or evidences)
+ */
+```
+- `loadResults()` — ⚪ Interno
+- `InstanciaTransfer()` — ⚪ Interno
+
+---
+
+
+### 🧩 Clase: `TestController`
+**Ubicación:** `src\main\java\es\uv\saic\web\TestController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Generates PDFs for all instances of a given process and task for admin user
+ * 
+ * @param auth The authentication object
+ * @return A string indicating the result of the operation
+ * @throws FileNotFoundException If a required file is not found
+ * @throws IOException If an I/O error occurs
+ * @throws InterruptedException If the thread is interrupted
+ */
+```
+- `generatePDF()` — 🟢 Endpoint
+
+---
+
+
+### 🧩 Clase: `WikiController`
+**Ubicación:** `src\main\java\es\uv\saic\web\WikiController.java`
+**Estado de revisión:** ⚠️ *Pendiente*
+
+#### 🔍 Métodos detectados:
+```
+/*
+ * Renders the wiki page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @return The name of the view to render
+ */
+```
+- `renderWiki()` — 🟢 Endpoint
+```
+/*
+ * Renders the wiki editor page
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @return The name of the view to render
+ */
+```
+- `renderWikiEditor()` — 🟢 Endpoint
+```
+/*
+ * Returns the wiki text for a given category
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param categoria The category of the wiki
+ * @return The wiki text
+ */
+```
+- `renderWiki()` — 🟢 Endpoint
+```
+/*
+ * Updates the wiki text for a given category
+ * 
+ * @param model The model to pass data to the view
+ * @param auth The authentication object
+ * @param cat The category of the wiki
+ * @param text The new wiki text
+ * @return The updated wiki object
+ */
+```
+- `updateWiki()` — 🟢 Endpoint
+
+---
+
+
+# 📈 Estadísticas finales
+
+- Total de clases: 18
+- Total de métodos: 347
+- Total de comentarios: 112
+
+✅ **Fin del reporte de carpeta.**

Некоторые файлы не были показаны из-за большого количества измененных файлов