udistrital / polux_cliente

Cliente angular del proyecto Polux
0 stars 0 forks source link

Implementar endpoint creado en JBPM #685

Closed diagutierrezro closed 3 weeks ago

diagutierrezro commented 4 weeks ago

Se requiere realizar la implementación del endpoint creado por Jhon el cual se solicita en #684, realizar consulta del endpoint e implementar en el reporte necesario.

Sub Tareas

Criterios de aceptación

Dependencias

Para finalizar este issue depende de que tan rápido Jhon realice el endpoint de JBPM

Requerimientos

No aplica

Definition of Ready - DoR

Definition of Done - DoD - Desarrollo

CrisEs2506 commented 3 weeks ago

SubTarea N°1: Llamar nuevo endpoint creado en JBPM.

http://busservicios.intranetoas.udistrital.edu.co:8282/wso2eiserver/services/servicios_academicos/coordinador_proyecto/20

Resultado:

image

Nota: Recordar este nuevo endpoint para el momento de mandar a producción.

CrisEs2506 commented 3 weeks ago

SubTarea N°2: Implementar en los reportes la información obtenida en el nuevo endpoint.

POLUX_CRUD

import ( "strconv" "time"

"github.com/astaxie/beego/orm"

)

type ReporteSolicitud struct { Id int orm:"column(id)" TrabajoGrado int orm:"column(trabajo_grado)" Titulo string orm:"column(titulo)" Modalidad string orm:"column(modalidad)" EstadoTrabajoGrado string orm:"column(estado_trabajo_grado)" IdEstudiante string orm:"column(id_estudiante)" NombreEstudiante string IdCoestudiante string orm:"column(id_coestudiante)" NombreCoestudiante string ProgramaAcademico string NombreCoordinador string DocenteDirector int orm:"column(docente_director)" NombreDocenteDirector string DocenteCodirector int orm:"column(docente_codirector)" NombreDocenteCodirector string Evaluador int orm:"column(evaluador)" NombreEvaluador string FechaSolicitud time.Time orm:"column(fecha_solicitud);type(timestamp without time zone)" FechaRevision time.Time orm:"column(fecha_revision);type(timestamp without time zone);null" Solicitud string orm:"column(tipo_solicitud)" Observacion string orm:"column(justificacion)" Respuesta string orm:"column(estado_solicitud)" }

func init() { orm.RegisterModel(new(ReporteSolicitud)) }

func GetReporteSolicitud() (map[string]interface{}, error) { o := orm.NewOrm()

var results []orm.Params

_, err := o.Raw(`
    WITH estudiantes AS (
        SELECT
            trabajo_grado,
            MAX(CASE WHEN row_number = 1 THEN estudiante ELSE NULL END) AS id_estudiante,
            MAX(CASE WHEN row_number = 2 THEN estudiante ELSE NULL END) AS id_coestudiante
        FROM (
            SELECT
                trabajo_grado,
                estudiante,
                ROW_NUMBER() OVER (PARTITION BY trabajo_grado ORDER BY estudiante) AS row_number
            FROM
                academica.estudiante_trabajo_grado
        ) sub
        GROUP BY
            trabajo_grado
    ),
    usuarios AS (
        SELECT
            trabajo_grado,
            MAX(CASE WHEN rol_trabajo_grado = 4593 THEN usuario ELSE NULL END) AS docente_director,
            MAX(CASE WHEN rol_trabajo_grado = 4596 THEN usuario ELSE NULL END) AS docente_codirector,
            MAX(CASE WHEN rol_trabajo_grado = 4595 THEN usuario ELSE NULL END) AS evaluador
        FROM
            academica.vinculacion_trabajo_grado
        GROUP BY
            trabajo_grado
    )

    SELECT 
        stg.id,
        stg.trabajo_grado,
        tg.titulo,
        mts.modalidad,
        tg.estado_trabajo_grado,
        e.id_estudiante,
        e.id_coestudiante,
        u.docente_director,
        u.docente_codirector,
        u.evaluador,
        stg.fecha AS fecha_solicitud,
        rs.fecha AS fecha_revision,
        mts.tipo_solicitud,
        rs.justificacion,
        rs.estado_solicitud
    FROM 
        academica.solicitud_trabajo_grado stg
    JOIN 
        academica.modalidad_tipo_solicitud mts
        ON stg.modalidad_tipo_solicitud = mts.id
    JOIN 
        academica.trabajo_grado tg
        ON stg.trabajo_grado = tg.id
    LEFT JOIN 
        academica.respuesta_solicitud rs
        ON stg.id = rs.solicitud_trabajo_grado
    LEFT JOIN 
        estudiantes e
        ON stg.trabajo_grado = e.trabajo_grado
    LEFT JOIN 
        usuarios u
        ON stg.trabajo_grado = u.trabajo_grado
    ORDER BY
        stg.id DESC`).Values(&results)

if err != nil {
    return nil, err
}

if len(results) == 0 {
    return map[string]interface{}{
        "Success": false,
        "Data":    []interface{}{},
        "Message": "No se encontraron Resultados",
    }, nil
}

var reporteSolicitud []ReporteSolicitud

for _, result := range results {
    v := ReporteSolicitud{}

    if val, ok := result["id"].(string); ok {
        v.Id, _ = strconv.Atoi(val)
    }

    if val, ok := result["trabajo_grado"].(string); ok {
        v.TrabajoGrado, _ = strconv.Atoi(val)
    }

    if val, ok := result["titulo"].(string); ok && val != "" {
        v.Titulo = val
    }

    if val, ok := result["modalidad"].(string); ok && val != "" {
        v.Modalidad = val
    }

    if val, ok := result["estado_trabajo_grado"].(string); ok && val != "" {
        v.EstadoTrabajoGrado = val
    }

    if val, ok := result["id_estudiante"].(string); ok && val != "" {
        v.IdEstudiante = val
    }

    if val, ok := result["id_coestudiante"].(string); ok && val != "" {
        v.IdCoestudiante = val
    }

    v.ProgramaAcademico = ""

    v.NombreCoordinador = ""

    if val, ok := result["docente_director"].(string); ok {
        v.DocenteDirector, _ = strconv.Atoi(val)
    }

    if val, ok := result["docente_codirector"].(string); ok && val != "" {
        v.DocenteCodirector, _ = strconv.Atoi(val)
    }

    if val, ok := result["evaluador"].(string); ok && val != "" {
        v.Evaluador, _ = strconv.Atoi(val)
    }

    if val, ok := result["fecha_solicitud"].(string); ok {
        fechaSolicitud, _ := time.Parse(time.RFC3339, val)
        v.FechaSolicitud = fechaSolicitud
    }

    if val, ok := result["fecha_revision"].(string); ok && val != "" {
        fechaRevision, _ := time.Parse(time.RFC3339, val)
        v.FechaRevision = fechaRevision
    }

    if val, ok := result["tipo_solicitud"].(string); ok && val != "" {
        v.Solicitud = val
    }

    if val, ok := result["justificacion"].(string); ok && val != "" {
        v.Observacion = val
    }

    if val, ok := result["estado_solicitud"].(string); ok && val != "" {
        v.Respuesta = val
    }

    reporteSolicitud = append(reporteSolicitud, v)
}

return map[string]interface{}{
    "Success": true,
    "Data":    reporteSolicitud,
}, nil

}


**POLUX_MID**

- **Modelo**

```Go
package models

import (
    "time"
)

type ReporteSolicitud struct {
    Id                      int    `orm:"column(id)"`
    TrabajoGrado            int    `orm:"column(trabajo_grado)"`
    Titulo                  string `orm:"column(titulo)"`
    Modalidad               string `orm:"column(modalidad)"`
    EstadoTrabajoGrado      string `orm:"column(estado_trabajo_grado)"`
    IdEstudiante            string `orm:"column(id_estudiante)"`
    NombreEstudiante        string
    IdCoestudiante          string `orm:"column(id_coestudiante)"`
    NombreCoestudiante      string
    ProgramaAcademico       string
    NombreCoordinador       string
    DocenteDirector         int `orm:"column(docente_director)"`
    NombreDocenteDirector   string
    DocenteCodirector       int `orm:"column(docente_codirector)"`
    NombreDocenteCodirector string
    Evaluador               int `orm:"column(evaluador)"`
    NombreEvaluador         string
    FechaSolicitud          time.Time `orm:"column(fecha_solicitud);type(timestamp without time zone)"`
    FechaRevision           time.Time `orm:"column(fecha_revision);type(timestamp without time zone);null"`
    Solicitud               string    `orm:"column(tipo_solicitud)"`
    Observacion             string    `orm:"column(justificacion)"`
    Respuesta               string    `orm:"column(estado_solicitud)"`
}
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() 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 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, &parametros); err != nil {
        logs.Error("Error al obtener Parametros: ", err.Error())
        return 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 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 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 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
}
CrisEs2506 commented 3 weeks ago

Resultado del Excel - Reporte Solicitud

ReporteSolicitud.xlsx

diagutierrezro commented 3 weeks ago

Gran trabajo Cristian, queda pendiente por revisar mas a profundidad los scripts realizados en el CRUD y los endpoints usados en el MID para poderle mostrar al cliente.