Closed diagutierrezro closed 1 month ago
SubTareas
Se creo el texto "Generar Reportes", "Generar Reporte General" y "Generar Reporte de Solicitudes" en la carpeta 'decorators' en el archivo "text_translate.js", para idioma español e inglés ("Generate Reports", "Generate General Report" y "Generate Request Report").
La vista "generar_reportes.html" fue creado un fragmento con CSS puro para que quedará igual al mockup, ya que las clases de Bootstrap presentaban conflicto con el centrado de los botones, quedando de la siguiente manera:
<style>
.button-container {
display: flex;
justify-content: center;
gap: 150px;
}
.custom-btn {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #28a745;
color: white;
border: none;
border-radius: 4px;
width: 200px;
text-align: center;
}
.custom-btn:hover {
background-color: #218838;
}
</style>
<div class="panel panel-default">
<div class="panel-heading">
{{'GENERAR_REPORTE' | translate}}
</div>
<div class="panel-body">
<div class="button-container">
<button type="button" class="custom-btn" ng-click="generarReporte.generar_reporte_general()">
{{'GENERAR_REPORTE_GENERAL' | translate}}
</button>
<button type="button" class="custom-btn" ng-click="generarReporte.generar_reporte_solicitud()">
{{'GENERAR_REPORTE_SOLICITUD' | translate}}
</button>
</div>
</div>
</div>
"reporte_general.go"
package controllers
import (
"github.com/astaxie/beego"
"github.com/udistrital/polux_mid/helpers"
)
// Reporte_generalController operations for Reporte_general
type ReporteGeneralController struct {
beego.Controller
}
// URLMapping ...
func (c *ReporteGeneralController) URLMapping() {
c.Mapping("Post", c.Post)
}
// Post ...
// @Title Create
// @Description create reporte_general
// @Success 201
// @Failure 403
// @router / [post]
func (c *ReporteGeneralController) Post() {
//Generar el archivo Excel usando el helper
if file, err := helpers.BuildReporteGeneral(); err == nil {
//Establecer el tipo de contenido para la descarga del archivo
c.Ctx.Output.ContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
//Establecer el nombre del archivo que se descargará
c.Ctx.Output.Header("Content-Disposition", "attachment; filename=ReporteGeneral.xlsx")
//Guardar el archivo Excel en un buffer (espacio) de memoria
if err := file.Write(c.Ctx.ResponseWriter); err != nil {
//Manejar errores en la escritura del archivo al Cliente
c.Data["json"] = "Error al generar el archivo."
c.Ctx.Output.SetStatus(500)
} else {
//Establecer el estado de éxito
c.Data["json"] = "Reporte generado correctamente."
c.Ctx.Output.SetStatus(201)
}
} else {
//Manejar errores al generar el reporte
c.Data["json"] = err.Error()
c.Ctx.Output.SetStatus(403)
}
c.ServeJSON()
}
package helpers
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"github.com/astaxie/beego/logs"
"github.com/udistrital/polux_mid/models"
"github.com/xuri/excelize/v2"
)
func BuildReporteGeneral() (*excelize.File, error) {
var reporteGeneral []models.ReporteGeneral
//Se traen todos los datos de reporte general
url := "/v1/reporte_general"
if err := GetRequestNew("PoluxCrudUrl", url, &reporteGeneral); err != nil {
logs.Error("Error al obtener ReporteGeneral: ", err.Error())
return nil, err
}
var parametros []models.Parametro
//Se trae los Estados, la Modalidad del Trabajo de Grado y las Areas de Conocimiento
url = "parametro?query=TipoParametroId__in:73|76|3|4&limit=0"
if err := GetRequestNew("UrlCrudParametros", url, ¶metros); err != nil {
logs.Error("Error al obtener Parametros: ", err.Error())
return nil, err
}
//Crear un mapa de parámetros para facilitar la búsqueda
parametroMap := make(map[int]string)
for _, parametro := range parametros {
parametroMap[parametro.Id] = parametro.Nombre
}
//Mapa para almacenar los nombres y carreras de estudiantes ya consultados
nombresCache := make(map[string]models.DatosBasicosEstudiante)
//Iterar sobre reporteGeneral y modificar los campos necesarios
for i, rg := range reporteGeneral {
if modalidadID, err := strconv.Atoi(rg.Modalidad); err == nil {
if nombre, ok := parametroMap[modalidadID]; ok {
reporteGeneral[i].Modalidad = nombre
}
}
if estadoID, err := strconv.Atoi(rg.EstadoTrabajoGrado); err == nil {
if nombre, ok := parametroMap[estadoID]; ok {
reporteGeneral[i].EstadoTrabajoGrado = nombre
}
}
if areaID, err := strconv.Atoi(rg.AreaConocimiento); err == nil {
if nombre, ok := parametroMap[areaID]; ok {
reporteGeneral[i].AreaConocimiento = nombre
}
}
//Procesar IdEstudiante
if rg.IdEstudiante != "" {
if datos, exists := nombresCache[rg.IdEstudiante]; exists {
//Si el nombre y carrera ya están en el cache, usarlos directamente
reporteGeneral[i].NombreEstudiante = datos.Nombre
reporteGeneral[i].ProgramaAcademico = datos.Carrera
} else {
//Si no están en el cache, obtenerlos y guardarlos
datos, err := obtenerDatosEstudiante(rg.IdEstudiante)
if err != nil {
logs.Error("Error al obtener datos del estudiante: ", err.Error())
} else {
reporteGeneral[i].NombreEstudiante = datos.Nombre
reporteGeneral[i].ProgramaAcademico = datos.Carrera
nombresCache[rg.IdEstudiante] = datos // Guardar en el cache
}
}
}
//Procesar IdCoestudiante (sin modificar ProgramaAcademico)
if rg.IdCoestudiante != "" {
if datos, exists := nombresCache[rg.IdCoestudiante]; exists {
//Si el nombre ya está en el cache, usarlo directamente
reporteGeneral[i].NombreCoestudiante = datos.Nombre
} else {
//Si no están en el cache, obtenerlos y guardarlos
datos, err := obtenerDatosEstudiante(rg.IdCoestudiante)
if err != nil {
logs.Error("Error al obtener datos del coestudiante: ", err.Error())
} else {
reporteGeneral[i].NombreCoestudiante = datos.Nombre
nombresCache[rg.IdCoestudiante] = datos // Guardar en el cache
}
}
}
}
//Traer docentes
docenteMap, err := obtenerDocentes()
if err != nil {
logs.Error("Error al obtener docentes: ", err.Error())
return nil, err
}
//Mapa para almacenar los nombres de carreras ya consultadas
carreraCache := make(map[string]string)
//Hubo la necesidad de iterar nuevamente sobre reporteGeneral, ya que se necesitaba que se añadiera primero el id de la carrera a ProgramaAcademico a través del anterior for, para luego obtener el nombre de la carrera y está fue la única manera (aunque a mi parecer no tan óptima)
for i, rg := range reporteGeneral {
//Obtener nombre de la carrera a partir del ID almacenado en ProgramaAcademico
if rg.ProgramaAcademico != "" {
if nombreCarrera, exists := carreraCache[rg.ProgramaAcademico]; exists {
//Si el nombre de la carrera ya está en el cache, usarlo directamente
reporteGeneral[i].ProgramaAcademico = nombreCarrera
} else {
//Si no está en el cache, obtenerlo y guardarlo
nombreCarrera, err := obtenerNombreCarrera(rg.ProgramaAcademico)
if err != nil {
logs.Error("Error al obtener el nombre de la carrera: ", err.Error())
} else {
reporteGeneral[i].ProgramaAcademico = nombreCarrera
carreraCache[rg.ProgramaAcademico] = nombreCarrera // Guardar en el cache
}
}
}
//Asignar nombres de docentes
if nombre, exists := docenteMap[rg.DocenteDirector]; exists {
reporteGeneral[i].NombreDocenteDirector = nombre
}
if nombre, exists := docenteMap[rg.DocenteCodirector]; exists {
reporteGeneral[i].NombreDocenteCodirector = nombre
}
if nombre, exists := docenteMap[rg.Evaluador]; exists {
reporteGeneral[i].NombreEvaluador = nombre
}
}
//Título de las Columnas del Excel
headers := map[string]string{
"A1": "Trabajo Grado",
"B1": "Título",
"C1": "Modalidad",
"D1": "Estado",
"E1": "ID Estudiante",
"F1": "Nombre Estudiante",
"G1": "ID Estudiante",
"H1": "Nombre Estudiante",
"I1": "Programa Academico",
"J1": "Area Conocimiento",
"K1": "ID Docente Director",
"L1": "Nombre Docente Director",
"M1": "ID Docente Codirector",
"N1": "Nombre Docente Codirector",
"O1": "ID Evaluador",
"P1": "Nombre Evaluador",
"Q1": "Fecha Inicio",
"R1": "Fecha Fin",
"S1": "Calificación 1",
"T1": "Calificación 2",
}
//Creación e Inicialización del Excel
file := excelize.NewFile()
//Definir el estilo para los Encabezados
style := &excelize.Style{
Fill: excelize.Fill{
Type: "pattern",
Color: []string{"#FFFF00"},
Pattern: 1,
},
Border: []excelize.Border{
{Type: "left", Color: "000000", Style: 1},
{Type: "top", Color: "000000", Style: 1},
{Type: "bottom", Color: "000000", Style: 1},
{Type: "right", Color: "000000", Style: 1},
},
}
//Precargar los estilos a la hoja de calculo
styleID, err := file.NewStyle(style)
if err != nil {
fmt.Println(err)
return nil, err
}
//Recorrer los headers y añadir a la hoja de cálculo del Excel
for k, v := range headers {
file.SetCellValue("Sheet1", k, v)
file.SetCellStyle("Sheet1", k, k, styleID) // Aplicar el estilo de fondo amarillo
}
//Recorrer cada elemento del Slice de ReporteGeneral y escribir en cada fila del Excel su respectiva información
for i := 0; i < len(reporteGeneral); i++ {
rowCount := i + 2
file.SetCellValue("Sheet1", fmt.Sprintf("A%v", rowCount), reporteGeneral[i].TrabajoGrado)
file.SetCellValue("Sheet1", fmt.Sprintf("B%v", rowCount), reporteGeneral[i].Titulo)
file.SetCellValue("Sheet1", fmt.Sprintf("C%v", rowCount), reporteGeneral[i].Modalidad)
file.SetCellValue("Sheet1", fmt.Sprintf("D%v", rowCount), reporteGeneral[i].EstadoTrabajoGrado)
file.SetCellValue("Sheet1", fmt.Sprintf("E%v", rowCount), reporteGeneral[i].IdEstudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("F%v", rowCount), reporteGeneral[i].NombreEstudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("G%v", rowCount), reporteGeneral[i].IdCoestudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("H%v", rowCount), reporteGeneral[i].NombreCoestudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("I%v", rowCount), reporteGeneral[i].ProgramaAcademico)
file.SetCellValue("Sheet1", fmt.Sprintf("J%v", rowCount), reporteGeneral[i].AreaConocimiento)
file.SetCellValue("Sheet1", fmt.Sprintf("K%v", rowCount), reporteGeneral[i].DocenteDirector)
file.SetCellValue("Sheet1", fmt.Sprintf("L%v", rowCount), reporteGeneral[i].NombreDocenteDirector)
file.SetCellValue("Sheet1", fmt.Sprintf("M%v", rowCount), reporteGeneral[i].DocenteCodirector)
file.SetCellValue("Sheet1", fmt.Sprintf("N%v", rowCount), reporteGeneral[i].NombreDocenteCodirector)
file.SetCellValue("Sheet1", fmt.Sprintf("O%v", rowCount), reporteGeneral[i].Evaluador)
file.SetCellValue("Sheet1", fmt.Sprintf("P%v", rowCount), reporteGeneral[i].NombreEvaluador)
file.SetCellValue("Sheet1", fmt.Sprintf("Q%v", rowCount), reporteGeneral[i].FechaInicio.Format("2006-01-02"))
file.SetCellValue("Sheet1", fmt.Sprintf("R%v", rowCount), reporteGeneral[i].FechaFin.Format("2006-01-02"))
file.SetCellValue("Sheet1", fmt.Sprintf("S%v", rowCount), reporteGeneral[i].CalificacionUno)
file.SetCellValue("Sheet1", fmt.Sprintf("T%v", rowCount), reporteGeneral[i].CalificacionDos)
}
//Guardar el archivo Excel en este caso en la raíz del proyecto
if err := file.SaveAs("ReporteGeneral.xlsx"); err != nil {
fmt.Println(err)
}
return file, nil
}
func obtenerDatosEstudiante(idEstudiante string) (models.DatosBasicosEstudiante, error) {
url := fmt.Sprintf("http://busservicios.intranetoas.udistrital.edu.co:8282/wso2eiserver/services/servicios_academicos/datos_basicos_estudiante/%s", idEstudiante)
resp, err := http.Get(url)
if err != nil {
return models.DatosBasicosEstudiante{}, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return models.DatosBasicosEstudiante{}, fmt.Errorf("Error al realizar la solicitud: %s", resp.Status)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return models.DatosBasicosEstudiante{}, err
}
var datos models.DatosEstudianteCollection
if err := xml.Unmarshal(body, &datos); err != nil {
return models.DatosBasicosEstudiante{}, err
}
if len(datos.DatosBasicosEstudiante) > 0 {
return datos.DatosBasicosEstudiante[0], nil
}
return models.DatosBasicosEstudiante{}, fmt.Errorf("No se encontraron datos para el estudiante %s", idEstudiante)
}
func obtenerNombreCarrera(idCarrera string) (string, error) {
url := fmt.Sprintf("http://busservicios.intranetoas.udistrital.edu.co:8282/wso2eiserver/services/servicios_academicos/carrera/%s", idCarrera)
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Error al realizar la solicitud: %s", resp.Status)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var carreraCollection struct {
Carrera struct {
Nombre string `xml:"nombre"`
} `xml:"carrera"`
}
if err := xml.Unmarshal(body, &carreraCollection); err != nil {
return "", err
}
return carreraCollection.Carrera.Nombre, nil
}
func obtenerDocentes() (map[int]string, error) {
url := "http://busservicios.intranetoas.udistrital.edu.co:8282/wso2eiserver/services/servicios_academicos/get_docentes_tg"
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error al realizar la solicitud: %s", resp.Status)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var docentes struct {
Docentes []struct {
ID int `xml:"id"`
Nombre string `xml:"NOMBRE"`
} `xml:"docente"`
}
if err := xml.Unmarshal(body, &docentes); err != nil {
return nil, err
}
docenteMap := make(map[int]string)
for _, docente := range docentes.Docentes {
docenteMap[docente.ID] = docente.Nombre
}
return docenteMap, nil
}
"reporte_solicitud.go"
package controllers
import (
"github.com/astaxie/beego"
"github.com/udistrital/polux_mid/helpers"
)
// Reporte_generalController operations for Reporte_general
type ReporteSolicitudController struct {
beego.Controller
}
// URLMapping ...
func (c *ReporteSolicitudController) URLMapping() {
c.Mapping("Post", c.Post)
}
// Post ...
// @Title Create
// @Description create reporte_general
// @Success 201
// @Failure 403
// @router / [post]
func (c *ReporteSolicitudController) Post() {
//Generar el archivo Excel usando el helper
if file, err := helpers.BuildReporteSolicitud(); err == nil {
//Establecer el tipo de contenido para la descarga del archivo
c.Ctx.Output.ContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
//Establecer el nombre del archivo que se descargará
c.Ctx.Output.Header("Content-Disposition", "attachment; filename=ReporteSolicitud.xlsx")
//Guardar el archivo Excel en un buffer (espacio) de memoria
if err := file.Write(c.Ctx.ResponseWriter); err != nil {
//Manejar errores en la escritura del archivo al Cliente
c.Data["json"] = "Error al generar el archivo."
c.Ctx.Output.SetStatus(500)
} else {
//Establecer el estado de éxito
c.Data["json"] = "Reporte generado correctamente."
c.Ctx.Output.SetStatus(201)
}
} else {
//Manejar errores al generar el reporte
c.Data["json"] = err.Error()
c.Ctx.Output.SetStatus(403)
}
c.ServeJSON()
}
package helpers
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"github.com/astaxie/beego/logs"
"github.com/udistrital/polux_mid/models"
"github.com/xuri/excelize/v2"
)
func BuildReporteSolicitud() (*excelize.File, error) {
var reporteSolicitud []models.ReporteSolicitud
//Se traen todos los datos de reporte solicitud del CRUD
url := "/v1/reporte_solicitud"
if err := GetRequestNew("PoluxCrudUrl", url, &reporteSolicitud); err != nil {
logs.Error("Error al obtener ReporteSolicitud: ", err.Error())
return nil, err
}
var parametros []models.Parametro
//Se trae los Estados, la Modalidades, los Tipo Solicitud y los Estados de Solicitud de Trabajo de Grado de Parametros
url = "parametro?query=TipoParametroId__in:73|76|77|78&limit=0"
if err := GetRequestNew("UrlCrudParametros", url, ¶metros); err != nil {
logs.Error("Error al obtener Parametros: ", err.Error())
return nil, err
}
//Crear un mapa de parámetros para facilitar la búsqueda
parametroMap := make(map[int]string)
for _, parametro := range parametros {
parametroMap[parametro.Id] = parametro.Nombre
}
//Mapa para almacenar los nombres y carreras de estudiantes ya consultados
nombresCache := make(map[string]models.DatosBasicosEstudiante)
//Iterar sobre reporteSolicitud y modificar los campos necesarios
for i, rs := range reporteSolicitud {
if modalidadID, err := strconv.Atoi(rs.Modalidad); err == nil {
if nombre, ok := parametroMap[modalidadID]; ok {
reporteSolicitud[i].Modalidad = nombre
}
}
if estadoID, err := strconv.Atoi(rs.EstadoTrabajoGrado); err == nil {
if nombre, ok := parametroMap[estadoID]; ok {
reporteSolicitud[i].EstadoTrabajoGrado = nombre
}
}
if tipoSolicitudID, err := strconv.Atoi(rs.Solicitud); err == nil {
if nombre, ok := parametroMap[tipoSolicitudID]; ok {
reporteSolicitud[i].Solicitud = nombre
}
}
if estadoSolicitudID, err := strconv.Atoi(rs.Respuesta); err == nil {
if nombre, ok := parametroMap[estadoSolicitudID]; ok {
reporteSolicitud[i].Respuesta = nombre
}
}
//Procesar IdEstudiante
if rs.IdEstudiante != "" {
if datos, exists := nombresCache[rs.IdEstudiante]; exists {
//Si el nombre y carrera ya están en el cache, usarlos directamente
reporteSolicitud[i].NombreEstudiante = datos.Nombre
reporteSolicitud[i].ProgramaAcademico = datos.Carrera
} else {
//Si no están en el cache, obtenerlos y guardarlos
datos, err := obtenerDatosEstudiante(rs.IdEstudiante)
if err != nil {
logs.Error("Error al obtener datos del estudiante: ", err.Error())
} else {
reporteSolicitud[i].NombreEstudiante = datos.Nombre
reporteSolicitud[i].ProgramaAcademico = datos.Carrera
nombresCache[rs.IdEstudiante] = datos // Guardar en el cache
}
}
}
//Procesar IdCoestudiante (sin modificar ProgramaAcademico)
if rs.IdCoestudiante != "" {
if datos, exists := nombresCache[rs.IdCoestudiante]; exists {
//Si el nombre ya está en el cache, usarlo directamente
reporteSolicitud[i].NombreCoestudiante = datos.Nombre
} else {
//Si no están en el cache, obtenerlos y guardarlos
datos, err := obtenerDatosEstudiante(rs.IdCoestudiante)
if err != nil {
logs.Error("Error al obtener datos del coestudiante: ", err.Error())
} else {
reporteSolicitud[i].NombreCoestudiante = datos.Nombre
nombresCache[rs.IdCoestudiante] = datos // Guardar en el cache
}
}
}
}
//Traer docentes
docenteMap, err := obtenerDocentes()
if err != nil {
logs.Error("Error al obtener docentes: ", err.Error())
return nil, err
}
//Mapa para almacenar los nombres de carreras ya consultadas
coordinadorCache := make(map[string]string)
//Mapa para almacenar los nombres de carreras ya consultadas
carreraCache := make(map[string]string)
//Hubo la necesidad de iterar nuevamente sobre reporteSolicitud, ya que se necesitaba que se añadiera primero el id de la carrera a ProgramaAcademico a través del anterior for, para luego obtener el nombre de la carrera y está fue la única manera (aunque a mi parecer no tan óptima)
for i, rs := range reporteSolicitud {
//Obtener nombre del coordinador a partir del ID almacenado en ProgramaAcademico
if rs.ProgramaAcademico != "" {
if nombreCoordinador, exists := coordinadorCache[rs.ProgramaAcademico]; exists {
//Si el nombre de la carrera ya está en el cache, usarlo directamente
reporteSolicitud[i].NombreCoordinador = nombreCoordinador
} else {
//Si no está en el cache, obtenerlo y guardarlo
nombreCoordinador, err := obtenerNombreCoordinador(rs.ProgramaAcademico)
if err != nil {
logs.Error("Error al obtener el nombre de la carrera: ", err.Error())
} else {
reporteSolicitud[i].NombreCoordinador = nombreCoordinador
coordinadorCache[rs.ProgramaAcademico] = nombreCoordinador // Guardar en el cache
}
}
}
//Obtener nombre de la carrera a partir del ID almacenado en ProgramaAcademico
if rs.ProgramaAcademico != "" {
if nombreCarrera, exists := carreraCache[rs.ProgramaAcademico]; exists {
//Si el nombre de la carrera ya está en el cache, usarlo directamente
reporteSolicitud[i].ProgramaAcademico = nombreCarrera
} else {
//Si no está en el cache, obtenerlo y guardarlo
nombreCarrera, err := obtenerNombreCarrera(rs.ProgramaAcademico)
if err != nil {
logs.Error("Error al obtener el nombre de la carrera: ", err.Error())
} else {
reporteSolicitud[i].ProgramaAcademico = nombreCarrera
carreraCache[rs.ProgramaAcademico] = nombreCarrera // Guardar en el cache
}
}
}
//Asignar nombres de docentes
if nombre, exists := docenteMap[rs.DocenteDirector]; exists {
reporteSolicitud[i].NombreDocenteDirector = nombre
}
if nombre, exists := docenteMap[rs.DocenteCodirector]; exists {
reporteSolicitud[i].NombreDocenteCodirector = nombre
}
if nombre, exists := docenteMap[rs.Evaluador]; exists {
reporteSolicitud[i].NombreEvaluador = nombre
}
}
//Título de las Columnas del Excel
headers := map[string]string{
"A1": "ID Solicitud",
"B1": "Trabajo Grado",
"C1": "Título",
"D1": "Modalidad",
"E1": "Estado Trabajo Grado",
"F1": "ID Estudiante",
"G1": "Nombre Estudiante",
"H1": "ID Estudiante",
"I1": "Nombre Estudiante",
"J1": "Programa Academico",
"K1": "Nombre Coordinador",
"L1": "ID Docente Director",
"M1": "Nombre Docente Director",
"N1": "ID Docente Codirector",
"O1": "Nombre Docente Codirector",
"P1": "ID Evaluador",
"Q1": "Nombre Evaluador",
"R1": "Fecha Solicitud",
"S1": "Fecha Revision",
"T1": "Concepto de Revision",
"U1": "Observaciones",
"V1": "Respuesta",
}
//Creación e Inicialización del Excel
file := excelize.NewFile()
//Definir el estilo para los Encabezados
style := &excelize.Style{
Fill: excelize.Fill{
Type: "pattern",
Color: []string{"#FFFF00"},
Pattern: 1,
},
Border: []excelize.Border{
{Type: "left", Color: "000000", Style: 1},
{Type: "top", Color: "000000", Style: 1},
{Type: "bottom", Color: "000000", Style: 1},
{Type: "right", Color: "000000", Style: 1},
},
}
//Precarsar los estilos a la hoja de calculo
styleID, err := file.NewStyle(style)
if err != nil {
fmt.Println(err)
return nil, err
}
//Recorrer los headers y añadir a la hoja de cálculo del Excel
for k, v := range headers {
file.SetCellValue("Sheet1", k, v)
file.SetCellStyle("Sheet1", k, k, styleID) // Aplicar el estilo de fondo amarillo
}
//Recorrer cada elemento del Slice de ReporteSolicitud y escribir en cada fila del Excel su respectiva información
for i := 0; i < len(reporteSolicitud); i++ {
rowCount := i + 2
file.SetCellValue("Sheet1", fmt.Sprintf("A%v", rowCount), reporteSolicitud[i].Id)
file.SetCellValue("Sheet1", fmt.Sprintf("B%v", rowCount), reporteSolicitud[i].TrabajoGrado)
file.SetCellValue("Sheet1", fmt.Sprintf("C%v", rowCount), reporteSolicitud[i].Titulo)
file.SetCellValue("Sheet1", fmt.Sprintf("D%v", rowCount), reporteSolicitud[i].Modalidad)
file.SetCellValue("Sheet1", fmt.Sprintf("E%v", rowCount), reporteSolicitud[i].EstadoTrabajoGrado)
file.SetCellValue("Sheet1", fmt.Sprintf("F%v", rowCount), reporteSolicitud[i].IdEstudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("G%v", rowCount), reporteSolicitud[i].NombreEstudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("H%v", rowCount), reporteSolicitud[i].IdCoestudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("I%v", rowCount), reporteSolicitud[i].NombreCoestudiante)
file.SetCellValue("Sheet1", fmt.Sprintf("J%v", rowCount), reporteSolicitud[i].ProgramaAcademico)
file.SetCellValue("Sheet1", fmt.Sprintf("K%v", rowCount), reporteSolicitud[i].NombreCoordinador)
file.SetCellValue("Sheet1", fmt.Sprintf("L%v", rowCount), reporteSolicitud[i].DocenteDirector)
file.SetCellValue("Sheet1", fmt.Sprintf("M%v", rowCount), reporteSolicitud[i].NombreDocenteDirector)
file.SetCellValue("Sheet1", fmt.Sprintf("N%v", rowCount), reporteSolicitud[i].DocenteCodirector)
file.SetCellValue("Sheet1", fmt.Sprintf("O%v", rowCount), reporteSolicitud[i].NombreDocenteCodirector)
file.SetCellValue("Sheet1", fmt.Sprintf("P%v", rowCount), reporteSolicitud[i].Evaluador)
file.SetCellValue("Sheet1", fmt.Sprintf("Q%v", rowCount), reporteSolicitud[i].NombreEvaluador)
file.SetCellValue("Sheet1", fmt.Sprintf("R%v", rowCount), reporteSolicitud[i].FechaSolicitud.Format("2006-01-02"))
file.SetCellValue("Sheet1", fmt.Sprintf("S%v", rowCount), reporteSolicitud[i].FechaRevision.Format("2006-01-02"))
file.SetCellValue("Sheet1", fmt.Sprintf("T%v", rowCount), reporteSolicitud[i].Solicitud)
file.SetCellValue("Sheet1", fmt.Sprintf("U%v", rowCount), reporteSolicitud[i].Observacion)
file.SetCellValue("Sheet1", fmt.Sprintf("V%v", rowCount), reporteSolicitud[i].Respuesta)
}
//Guardar el archivo Excel en este caso en la raíz del proyecto
if err := file.SaveAs("ReporteSolicitud.xlsx"); err != nil {
fmt.Println(err)
}
return file, nil
}
func obtenerNombreCoordinador(idCarrera string) (string, error) {
url := fmt.Sprintf("http://busservicios.intranetoas.udistrital.edu.co:8282/wso2eiserver/services/servicios_academicos/coordinador_proyecto/%s", idCarrera)
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Error al realizar la solicitud: %s", resp.Status)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var coordinadorCollection struct {
Coordinador struct {
Nombre string `xml:"nombre_coordinador"`
} `xml:"coordinador"`
}
if err := xml.Unmarshal(body, &coordinadorCollection); err != nil {
return "", err
}
return coordinadorCollection.Coordinador.Nombre, nil
}
'use strict';
/**
* @ngdoc controller
* @name poluxClienteApp.controller:GenerarReporteCtrl
* @description
* # GenerarReporteCtrl
* Controller of the poluxClienteApp
* Controlador que permite al coordinador generar reportes generales y de solicitudes
* @requires $scope
* @requires $window
* @requires decorators/poluxClienteApp.decorator:TextTranslate
* @requires services/poluxMidService.service:poluxMidRequest
* @requires services/poluxService.service:nuxeoClient
*/
angular.module('poluxClienteApp').controller('GenerarReporteCtrl',
function ($scope, $window, poluxMidRequest) {
var ctrl = this;
/**
* @ngdoc method
* @name generar_reporte_general
* @methodOf poluxClienteApp.controller:GenerarReporteCtrl
* @description
* Esta función llama al endpoint de POLUX_MID correspondiente de generar y descargar el Reporte General en un archivo Excel.
* @returns {undefined} No retorna nigún valor.
*/
ctrl.generar_reporte_general = function() {
poluxMidRequest.post("reporte_general", {}, { responseType: 'blob' }).then(function(response) {
//Usamos el objeto Blob para crear un archivo a partir de la respuesta de la solicitud HTTP
var blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
var downloadUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
//Creamos un enlace (<a>) de descarga dinámicamente, hacemos clic y luego lo eliminamos del DOM para descargar el archivo sin recargar la página
a.href = downloadUrl;
a.download = "ReporteGeneral.xlsx"; //Nombre del archivo
document.body.appendChild(a);
a.click();
//Eliminar el enlace después de descargar
document.body.removeChild(a);
}).catch(function(error) {
console.error('Error al generar el reporte general: ', error);
});
}
/**
* @ngdoc method
* @name generar_reporte_solicitud
* @methodOf poluxClienteApp.controller:GenerarReporteCtrl
* @description
* Esta función llama al endpoint de POLUX_MID correspondiente de generar y descargar el Reporte Solicitud en un archivo Excel.
* @returns {undefined} No retorna nigún valor.
*/
ctrl.generar_reporte_general = function() {
poluxMidRequest.post("reporte_solicitud", {}, { responseType: 'blob' }).then(function(response) {
//Usamos el objeto Blob para crear un archivo a partir de la respuesta de la solicitud HTTP
var blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
var downloadUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
//Creamos un enlace (<a>) de descarga dinámicamente, hacemos clic y luego lo eliminamos del DOM para descargar el archivo sin recargar la página
a.href = downloadUrl;
a.download = "ReporteSolicitud.xlsx"; //Nombre del archivo
document.body.appendChild(a);
a.click();
// Eliminar el enlace después de descargar
document.body.removeChild(a);
}).catch(function(error) {
console.error('Error al generar el reporte de solicitudes: ', error);
});
}
}
);
Nota: Al parecer algunos servicios que son utilizados para generar los reportes se encuentran caídos por lo que no se pudo comprobar el funcionamiento adecuado del nuevo módulo creado (se adjunta evidencia):
Se continuará revisión de la vista del modulo de reportes en otra issue, buen trabajo Cristian.
Se requiere realizar la implementación del modulo de reportes teniendo en cuenta los mockups creados en #724 la cual debe permitir generar y descargar los reportes que se requieran.
Sub Tareas
Criterios de aceptación
Requerimientos
No aplica
Definition of Ready - DoR
Definition of Done - DoD - Desarrollo