-- Parche 077
-- Recupera exclusivamente las funciones y procedimientos almacenados que deben
-- acompañar a un respaldo integral. Es idempotente y no modifica tablas ni datos.
DELIMITER $$
DROP FUNCTION IF EXISTS `fn_limitar_texto_150`$$
CREATE DEFINER=CURRENT_USER FUNCTION `fn_limitar_texto_150`(p_texto TEXT) RETURNS varchar(150) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
  DECLARE v_texto TEXT;
  DECLARE v_corte VARCHAR(150);

  SET v_texto = TRIM(REPLACE(REPLACE(REPLACE(IFNULL(p_texto, ''), CHAR(13), ' '), CHAR(10), ' '), '  ', ' '));

  WHILE LOCATE('  ', v_texto) > 0 DO
    SET v_texto = REPLACE(v_texto, '  ', ' ');
  END WHILE;

  IF CHAR_LENGTH(v_texto) <= 150 THEN
    RETURN v_texto;
  END IF;

  SET v_corte = LEFT(v_texto, 150);

  IF LOCATE(' ', REVERSE(v_corte)) > 0 THEN
    SET v_corte = LEFT(v_corte, 150 - LOCATE(' ', REVERSE(v_corte)));
  END IF;

  RETURN TRIM(v_corte);
END$$

DROP FUNCTION IF EXISTS `fn_limitar_texto_250`$$
CREATE DEFINER=CURRENT_USER FUNCTION `fn_limitar_texto_250`(p_texto TEXT) RETURNS varchar(250) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
  DECLARE v_texto TEXT;
  DECLARE v_corte VARCHAR(250);

  SET v_texto = TRIM(REPLACE(REPLACE(REPLACE(IFNULL(p_texto, ''), CHAR(13), ' '), CHAR(10), ' '), '  ', ' '));

  WHILE LOCATE('  ', v_texto) > 0 DO
    SET v_texto = REPLACE(v_texto, '  ', ' ');
  END WHILE;

  IF CHAR_LENGTH(v_texto) <= 250 THEN
    RETURN v_texto;
  END IF;

  SET v_corte = LEFT(v_texto, 250);

  IF LOCATE(' ', REVERSE(v_corte)) > 0 THEN
    SET v_corte = LEFT(v_corte, 250 - LOCATE(' ', REVERSE(v_corte)));
  END IF;

  RETURN TRIM(v_corte);
END$$

DROP PROCEDURE IF EXISTS `spCrearAsistencia`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `spCrearAsistencia`(IN xFECHA DATE)
    SQL SECURITY INVOKER
BEGIN
  DECLARE CANT INT DEFAULT 0;
  DECLARE xANIO SMALLINT UNSIGNED;
  DECLARE REGISTROS_CREADOS INT DEFAULT 0;

  IF xFECHA IS NULL THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'La fecha de asistencia no puede ser NULL';
  END IF;

  SET xANIO = EXTRACT(YEAR FROM xFECHA);

  IF DAYOFWEEK(xFECHA) IN (1, 7) THEN
    SELECT 'ok2' AS resultado,
           xFECHA AS fecha,
           0 AS registros_creados,
           'No se crea asistencia para sabado o domingo.' AS mensaje;
  ELSE
    SELECT COUNT(*)
      INTO CANT
    FROM asistencia_estudiante ae
    INNER JOIN matricula m ON m.id_matricula = ae.id_matricula
    WHERE ae.fecha = xFECHA
      AND ae.codigo_control = 'DIARIA'
      AND m.id_anio_lectivo = xANIO;

    IF CANT = 0 THEN
      INSERT INTO asistencia_estudiante (
        fecha,
        id_matricula,
        codigo_control,
        id_tipo_asistencia,
        id_estado_asistencia,
        hora_ingreso,
        hora_salida,
        id_docente_tutor,
        ya_reg_ingreso,
        ya_reg_salida,
        observacion
      )
      SELECT
        xFECHA,
        m.id_matricula,
        'DIARIA',
        1,
        3,
        NULL,
        NULL,
        m.cod_docente_tutor,
        0,
        0,
        NULL
      FROM matricula m
      WHERE m.id_anio_lectivo = xANIO;

      SET REGISTROS_CREADOS = ROW_COUNT();

      SELECT 'ok' AS resultado,
             xFECHA AS fecha,
             REGISTROS_CREADOS AS registros_creados,
             'Asistencia diaria creada correctamente.' AS mensaje;
    ELSE
      SELECT 'ok2' AS resultado,
             xFECHA AS fecha,
             0 AS registros_creados,
             'La asistencia diaria ya existe para la fecha indicada.' AS mensaje;
    END IF;
  END IF;
END$$

DROP PROCEDURE IF EXISTS `sp_cneb_sugerir_conclusion_nota`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_cneb_sugerir_conclusion_nota`(IN p_id_nota INT UNSIGNED)
    SQL SECURITY INVOKER
BEGIN
  CALL sp_sugerir_conclusiones_por_evaluacion_250(p_id_nota);
END$$

DROP PROCEDURE IF EXISTS `sp_conv_generar_reporte_proteccion_periodo`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_conv_generar_reporte_proteccion_periodo`(
  IN p_periodo_reporte_id SMALLINT UNSIGNED,
  IN p_elaborado_por_persona_id INT UNSIGNED
)
    SQL SECURITY INVOKER
BEGIN
  DECLARE v_solicitud_id INT UNSIGNED;
  DECLARE v_institucion_id INT UNSIGNED DEFAULT 1;
  DECLARE v_numero_reporte TINYINT UNSIGNED;
  DECLARE v_codigo_reporte VARCHAR(80);
  DECLARE v_reporte_id BIGINT UNSIGNED;

  SELECT solicitud_reporte_id, numero_reporte
    INTO v_solicitud_id, v_numero_reporte
  FROM conv_periodo_reporte_proteccion
  WHERE periodo_reporte_id = p_periodo_reporte_id
  LIMIT 1;

  IF v_solicitud_id IS NULL THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'El periodo de reporte no existe.';
  END IF;

  SET v_codigo_reporte = CONCAT('REP-IE0003-UGEL-MP-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s'), '-', LPAD(v_numero_reporte, 2, '0'));

  INSERT INTO conv_reporte_proteccion (
    solicitud_reporte_id, periodo_reporte_id, institucion_id, codigo_reporte,
    fecha_elaboracion, estado, elaborado_por_persona_id, observacion
  ) VALUES (
    v_solicitud_id, p_periodo_reporte_id, v_institucion_id, v_codigo_reporte,
    NOW(), 'BORRADOR', p_elaborado_por_persona_id,
    'Reporte generado automaticamente a partir de expedientes marcados para reporte externo.'
  );

  SET v_reporte_id = LAST_INSERT_ID();

  INSERT IGNORE INTO conv_reporte_proteccion_detalle (
    reporte_proteccion_id, expediente_id, id_estudiante, categoria_proteccion_id,
    resumen_caso, acciones_realizadas, estado_atencion, observacion_reservada
  )
  SELECT
    v_reporte_id,
    exp.expediente_id,
    exp.estudiante_id,
    ecp.categoria_proteccion_id,
    LEFT(COALESCE(exp.descripcion_proteccion, exp.motivo_apertura), 1000) AS resumen_caso,
    (
      SELECT GROUP_CONCAT(CONCAT(DATE_FORMAT(ape.fecha_accion, '%d/%m/%Y'), ': ', ape.tipo_accion, ' - ', LEFT(ape.descripcion, 120)) SEPARATOR ' | ')
      FROM conv_accion_proteccion_estudiante ape
      WHERE ape.expediente_id = exp.expediente_id
    ) AS acciones_realizadas,
    CASE
      WHEN exp.estado = 'Cerrado' THEN 'CERRADO'
      WHEN exp.estado = 'Derivado' THEN 'DERIVADO'
      WHEN exp.estado = 'En seguimiento' THEN 'EN_SEGUIMIENTO'
      ELSE 'IDENTIFICADO'
    END AS estado_atencion,
    'Informacion reservada. Uso exclusivo institucional, UGEL y Ministerio Publico segun solicitud.'
  FROM conv_expediente_convivencia exp
  INNER JOIN conv_expediente_categoria_proteccion ecp ON ecp.expediente_id = exp.expediente_id
  INNER JOIN conv_periodo_reporte_proteccion prp ON prp.periodo_reporte_id = p_periodo_reporte_id
  WHERE exp.requiere_reporte_externo = 1
    AND DATE(COALESCE(exp.fecha_hecho, exp.fecha_apertura)) BETWEEN prp.fecha_inicio AND prp.fecha_fin;

  SELECT v_reporte_id AS reporte_proteccion_id, v_codigo_reporte AS codigo_reporte;
END$$

DROP PROCEDURE IF EXISTS `sp_conv_marcar_expediente_reporte_proteccion`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_conv_marcar_expediente_reporte_proteccion`(
  IN p_expediente_id INT UNSIGNED,
  IN p_categoria_codigo VARCHAR(80),
  IN p_nivel_valoracion VARCHAR(20),
  IN p_fecha_deteccion DATE,
  IN p_descripcion_valoracion TEXT,
  IN p_registrado_por_persona_id INT UNSIGNED
)
    SQL SECURITY INVOKER
BEGIN
  DECLARE v_categoria_id SMALLINT UNSIGNED;
  DECLARE v_nivel VARCHAR(20);

  SELECT categoria_proteccion_id
    INTO v_categoria_id
  FROM conv_categoria_proteccion_estudiante
  WHERE codigo = p_categoria_codigo
    AND activo = 1
  LIMIT 1;

  IF v_categoria_id IS NULL THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'La categoria de proteccion indicada no existe o esta inactiva.';
  END IF;

  SET v_nivel = UPPER(COALESCE(p_nivel_valoracion, 'MEDIO'));
  IF v_nivel NOT IN ('BAJO','MEDIO','ALTO','CRITICO') THEN
    SET v_nivel = 'MEDIO';
  END IF;

  INSERT INTO conv_expediente_categoria_proteccion (
    expediente_id, categoria_proteccion_id, fecha_deteccion, nivel_valoracion,
    requiere_reporte_ugel, requiere_reporte_ministerio_publico, descripcion_valoracion,
    registrado_por_persona_id
  ) VALUES (
    p_expediente_id, v_categoria_id, COALESCE(p_fecha_deteccion, CURDATE()), v_nivel,
    1,
    CASE WHEN v_nivel IN ('ALTO','CRITICO') THEN 1 ELSE 0 END,
    p_descripcion_valoracion,
    p_registrado_por_persona_id
  )
  ON DUPLICATE KEY UPDATE
    fecha_deteccion = VALUES(fecha_deteccion),
    nivel_valoracion = VALUES(nivel_valoracion),
    requiere_reporte_ugel = VALUES(requiere_reporte_ugel),
    requiere_reporte_ministerio_publico = VALUES(requiere_reporte_ministerio_publico),
    descripcion_valoracion = VALUES(descripcion_valoracion),
    registrado_por_persona_id = VALUES(registrado_por_persona_id);

  UPDATE conv_expediente_convivencia
  SET requiere_reporte_externo = 1,
      prioridad = CASE WHEN v_nivel = 'CRITICO' THEN 'CRITICA' WHEN v_nivel = 'ALTO' THEN 'ALTA' ELSE prioridad END,
      nivel_confidencialidad = CASE WHEN v_nivel IN ('ALTO','CRITICO') THEN 'ESTRICTO' ELSE nivel_confidencialidad END,
      nivel_proteccion = CASE
        WHEN p_categoria_codigo IN ('INTENTO_SUICIDIO','AUTOLESIONES_CORTES') THEN 'SALUD_MENTAL'
        WHEN p_categoria_codigo IN ('DESAMPARO_DERECHOS') THEN 'RIESGO_DESPROTECCION'
        WHEN p_categoria_codigo IN ('MALTRATO_VIOLENCIA') THEN 'VIOLENCIA'
        ELSE nivel_proteccion
      END
  WHERE expediente_id = p_expediente_id;
END$$

DROP PROCEDURE IF EXISTS `sp_registrar_asistencia_diaria`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_registrar_asistencia_diaria`(
  IN p_id_matricula INT UNSIGNED,
  IN p_fecha DATE,
  IN p_hora_ingreso TIME,
  IN p_hora_salida TIME,
  IN p_observacion VARCHAR(255)
)
    SQL SECURITY INVOKER
BEGIN
  DECLARE v_id_nivel CHAR(3);
  DECLARE v_id_anio_lectivo SMALLINT UNSIGNED;
  DECLARE v_hora_max TIME;
  DECLARE v_estado TINYINT UNSIGNED DEFAULT 1;

  SELECT a.id_nivel, m.id_anio_lectivo
    INTO v_id_nivel, v_id_anio_lectivo
  FROM matricula m
  INNER JOIN aula a ON a.id_aula = m.id_aula
  WHERE m.id_matricula = p_id_matricula
  LIMIT 1;

  SELECT CASE
           WHEN v_id_nivel = 'PRI' THEN c.hora_ingreso_max_pri
           WHEN v_id_nivel = 'SEC' THEN c.hora_ingreso_max_sec
           ELSE c.hora_ingreso_max_pri
         END
    INTO v_hora_max
  FROM asistencia_hora_config c
  WHERE c.id_anio_lectivo = v_id_anio_lectivo
    AND c.estado = 1
  ORDER BY c.id_asistencia_hora_config DESC
  LIMIT 1;

  IF p_hora_ingreso IS NULL THEN
    SET v_estado = 3;
  ELSEIF v_hora_max IS NOT NULL AND p_hora_ingreso > v_hora_max THEN
    SET v_estado = 2;
  ELSE
    SET v_estado = 1;
  END IF;

  INSERT INTO asistencia_estudiante (
    fecha,
    id_matricula,
    codigo_control,
    id_tipo_asistencia,
    id_estado_asistencia,
    hora_ingreso,
    hora_salida,
    observacion,
    ya_reg_ingreso,
    ya_reg_salida
  ) VALUES (
    p_fecha,
    p_id_matricula,
    'DIARIA',
    1,
    v_estado,
    p_hora_ingreso,
    p_hora_salida,
    p_observacion,
    IF(p_hora_ingreso IS NULL, 0, 1),
    IF(p_hora_salida IS NULL, 0, 1)
  )
  ON DUPLICATE KEY UPDATE
    id_estado_asistencia = VALUES(id_estado_asistencia),
    hora_ingreso = VALUES(hora_ingreso),
    hora_salida = VALUES(hora_salida),
    observacion = VALUES(observacion),
    ya_reg_ingreso = VALUES(ya_reg_ingreso),
    ya_reg_salida = VALUES(ya_reg_salida);
END$$

DROP PROCEDURE IF EXISTS `sp_sugerir_conclusiones_manual_250`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_sugerir_conclusiones_manual_250`(
  IN p_nivel_codigo VARCHAR(20),
  IN p_ciclo_codigo VARCHAR(10),
  IN p_competencia_codigo VARCHAR(100),
  IN p_calificacion_codigo VARCHAR(5)
)
    SQL SECURITY INVOKER
BEGIN
  SELECT
    n.nombre AS nivel,
    ci.codigo AS ciclo,
    co.nombre AS competencia,
    l.codigo AS calificacion,
    o.numero_opcion,
    o.enfoque,
    fn_limitar_texto_250(REPLACE(o.texto_plantilla, '{{COMPETENCIA}}', LOWER(COALESCE(co.nombre_corto_conclusion, co.nombre)))) AS conclusion_sugerida,
    CHAR_LENGTH(fn_limitar_texto_250(REPLACE(o.texto_plantilla, '{{COMPETENCIA}}', LOWER(COALESCE(co.nombre_corto_conclusion, co.nombre))))) AS caracteres,
    'SI' AS cumple_250
  FROM cneb_nivel n
  INNER JOIN cneb_ciclo ci ON ci.codigo = p_ciclo_codigo
  INNER JOIN cneb_competencia co ON co.codigo = p_competencia_codigo OR co.codigo_script = p_competencia_codigo
  INNER JOIN cneb_logro_calificacion l ON l.codigo = p_calificacion_codigo
  INNER JOIN cneb_regla_conclusion rc ON rc.id_cneb_nivel = n.id_cneb_nivel AND rc.logro_codigo = l.codigo AND rc.activo = 1
  INNER JOIN cneb_opcion_conclusion_descriptiva o
    ON o.id_cneb_nivel = n.id_cneb_nivel
   AND o.logro_codigo = l.codigo
   AND o.activo = 1
  WHERE n.codigo = CASE UPPER(p_nivel_codigo)
    WHEN 'INICIAL' THEN 'INI'
    WHEN 'PRIMARIA' THEN 'PRI'
    WHEN 'SECUNDARIA' THEN 'SEC'
    ELSE UPPER(p_nivel_codigo)
  END
    AND rc.requiere_conclusion = 1
  ORDER BY o.numero_opcion
  LIMIT 3;
END$$

DROP PROCEDURE IF EXISTS `sp_sugerir_conclusiones_por_evaluacion_250`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_sugerir_conclusiones_por_evaluacion_250`(IN p_id_evaluacion BIGINT UNSIGNED)
    SQL SECURITY INVOKER
BEGIN
  SELECT
    ne.id_nota AS id_evaluacion,
    COALESCE(NULLIF(p.nombre_completo, ''), TRIM(CONCAT_WS(' ', p.apellido_paterno, p.apellido_materno, p.nombres))) AS estudiante,
    cn.nombre AS nivel,
    ci.codigo AS ciclo,
    g.descripcion AS grado,
    s.nombre_corto AS seccion,
    ar.nombre AS area,
    c.descripcion AS competencia,
    ne.nota_literal AS calificacion,
    o.numero_opcion,
    o.enfoque,
    fn_limitar_texto_250(REPLACE(o.texto_plantilla, '{{COMPETENCIA}}', LOWER(COALESCE(cc.nombre_corto_conclusion, cc.nombre, c.descripcion)))) AS conclusion_sugerida,
    CHAR_LENGTH(fn_limitar_texto_250(REPLACE(o.texto_plantilla, '{{COMPETENCIA}}', LOWER(COALESCE(cc.nombre_corto_conclusion, cc.nombre, c.descripcion))))) AS caracteres,
    'SI' AS cumple_250
  FROM nota_estudiante ne
  INNER JOIN matricula m ON m.id_matricula = ne.id_matricula
  INNER JOIN aula au ON au.id_aula = m.id_aula
  INNER JOIN grado g ON g.id_grado = au.id_grado
  INNER JOIN seccion s ON s.id_seccion = au.id_seccion
  INNER JOIN estudiante e ON e.id_estudiante = m.id_estudiante
  INNER JOIN persona p ON p.id_persona = e.id_persona
  INNER JOIN area_curricular ar ON ar.id_area = ne.id_area
  LEFT JOIN competencia c ON c.id_competencia = ne.id_competencia
  LEFT JOIN cneb_competencia cc ON cc.id_cneb_competencia = c.id_cneb_competencia
  LEFT JOIN cneb_nivel cn ON cn.codigo = au.id_nivel
  LEFT JOIN cneb_ciclo ci ON ci.codigo = CASE
    WHEN au.id_nivel = 'INI' THEN 'II'
    WHEN au.id_nivel = 'PRI' AND au.id_grado IN (1,2) THEN 'III'
    WHEN au.id_nivel = 'PRI' AND au.id_grado IN (3,4) THEN 'IV'
    WHEN au.id_nivel = 'PRI' AND au.id_grado IN (5,6) THEN 'V'
    WHEN au.id_nivel = 'SEC' AND au.id_grado IN (7,8) THEN 'VI'
    WHEN au.id_nivel = 'SEC' AND au.id_grado IN (9,10,11) THEN 'VII'
    ELSE NULL
  END
  INNER JOIN cneb_regla_conclusion rc ON rc.id_cneb_nivel = cn.id_cneb_nivel AND rc.logro_codigo = ne.nota_literal AND rc.activo = 1
  INNER JOIN cneb_opcion_conclusion_descriptiva o
    ON o.id_cneb_nivel = cn.id_cneb_nivel
   AND o.logro_codigo = ne.nota_literal
   AND o.activo = 1
  WHERE ne.id_nota = p_id_evaluacion
    AND rc.requiere_conclusion = 1
  ORDER BY o.numero_opcion
  LIMIT 3;
END$$

DROP PROCEDURE IF EXISTS `sp_sugerir_conclusion_manual`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_sugerir_conclusion_manual`(
  IN p_nivel_codigo VARCHAR(20),
  IN p_ciclo_codigo VARCHAR(10),
  IN p_competencia_codigo VARCHAR(100),
  IN p_calificacion_codigo VARCHAR(5),
  IN p_nombre_estudiante VARCHAR(250)
)
    SQL SECURITY INVOKER
BEGIN
  SELECT
    p_nombre_estudiante AS estudiante,
    n.nombre AS nivel,
    ci.codigo AS ciclo,
    co.nombre AS competencia,
    l.codigo AS calificacion,
    COALESCE(rc.requiere_conclusion, 0) AS requiere_conclusion,
    fn_limitar_texto_150(
      CASE
        WHEN COALESCE(rc.requiere_conclusion, 0) = 0 THEN
          CONCAT('La calificacion ', l.codigo, ' no requiere conclusion descriptiva obligatoria en ', n.nombre, '.')
        ELSE
          CONCAT(
            p_nombre_estudiante, ' ', COALESCE(pc.texto_inicio, 'requiere acompanamiento en'), ' ', co.nombre,
            ' segun estandar del ciclo ', ci.codigo, '. ',
            COALESCE(pc.texto_recomendacion, 'Brindar retroalimentacion especifica.')
          )
      END
    ) AS conclusion_sugerida,
    CHAR_LENGTH(fn_limitar_texto_150(
      CASE
        WHEN COALESCE(rc.requiere_conclusion, 0) = 0 THEN
          CONCAT('La calificacion ', l.codigo, ' no requiere conclusion descriptiva obligatoria en ', n.nombre, '.')
        ELSE
          CONCAT(
            p_nombre_estudiante, ' ', COALESCE(pc.texto_inicio, 'requiere acompanamiento en'), ' ', co.nombre,
            ' segun estandar del ciclo ', ci.codigo, '. ',
            COALESCE(pc.texto_recomendacion, 'Brindar retroalimentacion especifica.')
          )
      END
    )) AS total_caracteres
  FROM cneb_nivel n
  INNER JOIN cneb_ciclo ci ON ci.codigo = p_ciclo_codigo
  INNER JOIN cneb_competencia co ON co.codigo = p_competencia_codigo OR co.codigo_script = p_competencia_codigo
  INNER JOIN cneb_logro_calificacion l ON l.codigo = p_calificacion_codigo
  LEFT JOIN cneb_regla_conclusion rc ON rc.id_cneb_nivel = n.id_cneb_nivel AND rc.logro_codigo = l.codigo AND rc.activo = 1
  LEFT JOIN cneb_plantilla_conclusion pc
    ON pc.id_cneb_nivel = n.id_cneb_nivel
   AND pc.logro_codigo = l.codigo
   AND pc.tipo = 'GENERAL'
   AND pc.scope_key = 'GENERAL'
   AND pc.activo = 1
  WHERE n.codigo = CASE UPPER(p_nivel_codigo)
    WHEN 'INICIAL' THEN 'INI'
    WHEN 'PRIMARIA' THEN 'PRI'
    WHEN 'SECUNDARIA' THEN 'SEC'
    ELSE UPPER(p_nivel_codigo)
  END
  LIMIT 1;
END$$

DROP PROCEDURE IF EXISTS `sp_sugerir_conclusion_por_evaluacion`$$
CREATE DEFINER=CURRENT_USER PROCEDURE `sp_sugerir_conclusion_por_evaluacion`(IN p_id_evaluacion BIGINT UNSIGNED)
    SQL SECURITY INVOKER
BEGIN
  SELECT
    v.id_nota AS id_evaluacion,
    v.estudiante,
    v.nivel,
    v.ciclo_codigo AS ciclo,
    v.area,
    v.competencia,
    v.calificacion,
    v.requiere_conclusion,
    v.conclusion_descriptiva AS conclusion_actual,
    v.conclusion_sugerida,
    CHAR_LENGTH(v.conclusion_sugerida) AS total_caracteres
  FROM vw_evaluaciones_conclusion_obligatoria v
  WHERE v.id_nota = p_id_evaluacion
  LIMIT 1;
END$$

DELIMITER ;

