lunes, 11 de septiembre de 2017

ABAP CDS: Introducción

“ Las aplicaciones van y vienen, pero los datos viven para siempre “
Cameron O’Rourke –ORACLE

Uno de los puntos más importantes a la hora de desarrollar aplicaciones ABAP es el diseño de las consultas SQL a la base de datos. Es de vital importancia diseñar un modelo de datos que nos permita realizar las consultas a la base de datos de manera óptima y que retorne solamente la información que necesitamos.

El modelo de datos en SAP tradicionalmente puede implementarse de dos formas. Utilizando la transacción SE11 para crear las tablas, vistas, estructuras, elementos de datos, etc… o directamente combinando sentencias SQL y utilizando los operadores INNER JOIN o LEFT OUTER JOIN.
Modelo de datos y sus posibles implementaciones

Si utilizamos la transacción SE11, los objetos que creamos en el diccionario podemos reutilizarlos en diferentes aplicaciones. Si utilizamos consultas SQL directamente en el código, pues solamente se podrán usar locamente en el programa que las implementemos. Todo dependerá de si queremos reutilizar las consulta SQL o no.

Da igual cuanto optimicemos el código de nuestra aplicación, si accedemos a los datos con un modelo de datos mal diseñado, serán necesarias realizar complicadísimas consultas SQL para extraer los datos que necesitamos y provocara un aumento exponencialmente del tiempo de ejecución.

Como explicaremos a continuación, con las CDS y las nuevas herramientas que nos ofrecen, seremos capaces de diseñar más fácilmente vistas ABAP CDS a partir de modelos de datos. Las nuevas vistas ABAP CDS podrán ser después consumirlas desde las aplicaciones ABAP o consumirlas como servicios externos con ODATA.


¿QUE ES ‘CORE DATA SERVICES’?


Es una infraestructura creada por SAP para definir y consumir modelos de datos persistentes en SAP HANA. Utiliza un lenguaje de definición de datos (DDL), un lenguaje de consulta (QL) y un lenguaje de control de datos (DCL) . CDS es independiente de la BD utilizada, aunque actualmente solamente lo soporta SAP HANA.

especificación Core Data Services

El objetivo de las vistas CDS es facilitar la implementación de los modelos de datos desarrollados en la fase de diseño. Las vistas CDS nos permiten implementar los modelos de entidad-relación de una forma mucho más eficiente que las tradicionales vistas de la transacción SE11.

Modelo de datos, implementación y consumo con CDS

Originalmente solamente era posible crear vistas CDS para SAP HANA y requería una conexión directa al servidor de HANA. Pero a partir de SAP NW ABAP 7.4 SP05 está disponible para ABAP y podemos crear vistas desde el servidor de aplicación ABAP con el entorno Eclipse+ADT. 

También se introduce un nuevo paradigma de programación llamado "Code Push-Down" o "Code To Data". Este nuevo paradigma es completamente opuesto al tradicional paradigma "Data to Code". Tradicionalmente, en el paradigma "Data to Code", accedemos a los datos de la base de datos a través de las sentencias SQL y los cargados en tablas internas, estructuras, variables, etc.... en la memoria del servidor de aplicación para después realizamos las operaciones o cálculos requeridos.

Data to core  vs Code to data

En el paradigma "Code Push-Down" podemos realizar operaciones y cálculos directamente en la capa de la base de datos, quedando la capa del servidor de aplicación libre para el tratamiento de los datos procesados. Esto es posible gracias a que la base de datos SAP HANA tiene un soporte para lenguajes procedurales directamente incluido en el kernel de la base de datos. 

Por ejemplo, gracias al paradigma "Code Push-Down" con la nueva implementación de OPEN SQL para ABAP podemos incluir operaciones aritméticas dentro de la instrucción SELECT que se ejecutaran al nivel de la base de datos y liberando los recursos del servidor de aplicación. En posteriores veremos cómo aprovecharnos de estas nuevas funcionalidades.

Operaciones aritméticas directamente en la sentencia SQL que se ejecutan a nivel de base de dato


Existen dos implementaciones diferentes de la misma especificación CDS: 

HANA CDS
  • Se crean directamente en la base de datos de SAP HANA 
  • Pueden consumirse externamente con servicios ODATA 
  • Para consumirlas desde una aplicación ABAP: 
  • Crear una vista externa en el DICC ABAP 
  • Enlazar la vista externa con la vista HANA CDS 
  • Consumir la vista externa utilizando sentencias OPEN SQL 
  • DOS órdenes de trasporte diferentes: 
  • La vista HANA CDS que se trasporta como una unidad de trasporte de HANA 
  • La vista externa que se trasporta con una orden de SAP (transacción STMS) 
HANA CDS, dos ordenes de trasporte para ABAP

ABAP CDS
  • Disponible desde SAP NW ABAP 7.4 SP05 
  • Se pueden definir y crear desde el servidor de aplicaciones ABAP con ECLIPSE + ADT 
  • Necesitamos de un servidor de aplicaciones ABAP para crearla 
  • Pueden consumirse externamente con servicios ODATA 
  • Son independientes de la base de datos 
  • Pueden utilizar tablas, vistas, elementos, etc…. definidos en el diccionario ABAP 
  • No requieren crear vistas externas 
  • Una única orden de trasporte estándar de SAP ( transacción STMS
ABAP CDS, una única orden de transporte

En esta serie de entradas sobre CDS nos centramos exclusivamente en vistas ABAP CDS.

¿Que ventajas tiene las vistas ABAP CDS sobre las vistas tradicionales del dicccinario que creamos desde la transacción SE11? Para empezar,  Las vistas creadas desde la transacción SE11 tienen limitaciones como que solamente podemos crear asociaciones de tipo INNER JOIN y que únicamente las vistas de mantenimiento son asociaciones de tipo LEFT OUTER JOIN.

En la siguiente tabla se muestran algunas de las características disponibles en las vistas ABAP CDS y que no se encuentran disponibles en las vistas de bases de datos tradicionales de la transacción SE11.

Algunas diferencias entre ABAP CDS y vistas de la transacción SE11
En el siguiente enlace podéis leer un listado completo de las características de ABAP CDS.


PASOS PARA CREAR Y CONSUMIR UNA VISTA ABAP CDS


Para comprobar si vuestro servidor de aplicación soporta las vistas ABAP CDS,  conectaros con el cliente SAPGUI y comprobar el nivel del módulo SAP_BASIS:
  • En el menú superior Sistemas -> STATUS -> Info Componentes
  • Comprobar que el nivel del módulo SAP_BASIS es 7.40 SP05 o superior.
Nivel módulo SAP_BASIS

Para crear vistas ABAP CDS necesitais tener instalado el IDE Eclipse y el plugin ABAP Development Tools y como hemos dicho conexión a un servidor de aplicación con SAP NW ABAP 7.4 SP05 o superior.

Pasos para crear la vista ABAP CDS:

1. Seleccionar el proyecto ABAP donde queremos crear la vista ABAP CDS
2. Seleccionar el paquete donde queremos crear la vista CDS.
    Botón derecho del ratón -> New -> Other ABAP Repository Object

3. Seleccionar el objeto"Data Definition" dentro de la carpeta "Core Data Services". 


Nota: Si estáis trabajando con un componente SAP_BASIS inferior a la versión 7.5 tenéis que seleccionar el objeto "Data Definition" o "DLL Source" dentro de la carpeta  "Diccionary".

4. Rellenar el nombre de la vista ABAP CDS y la descripción


5. Seleccionar o crear la orden de trasporte.

6. Por defecto tenemos varias plantillas disponibles para crear las vistas ABAP CDS.
    Seleccionamos la plantilla "Define view" y pulsamos finalizar.


7. Se abrirá una nueva ventana con el siguiente código.

vista ABAP CDS

8. Para implementar la vista ABAP CDS:
  1. Cambiar el texto "sql_view_name" por el nombre que tendrá la vista en el diccionario ABAP. IMPORTANTE: El nombre de la vista en el diccionario ABAP no puede ser el mismo que el nombre que hemos dado a la vista ABAP CDS en el paso 4.
  2. Reemplazar "data_source_name" por el nombre de la tabla de la base de datos 
  3. Para referenciar los campos se utiliza el punto (‘.’) en vez de ('~')
  4. Las columnas que recuperamos en la consulta se definen dentro de las llaves {}.
  5. Después de las llaves {} podemos incluir la cláusula WHERE.
  6. Los comentarios empiezan por // para una línea o /*   */ para un bloque

9. Grabar y activar.


En el diccionario ABAP las vistas ABAP CDS se denominan Vistas SQL DDL. Una vez activada la vista en Eclipse ya podemos ver nuestra vista desde la transacción SE11 y ejecutarla y acceder a su definición en SQL desde el menú Detalles -> ABAP Create, pero no se puede modificar la vista ABAP CDS desde el diccionario ABAP, solamente desde ECLIPSE.

Vista ABAP CDS desde la transacción SE11

Desde nuestras aplicaciones ABAP, las vistas ABAP CDS pueden consumirse con sentencias OPEN SQL como cualquier vista o tabla del diccionario ABAP. También pueden utilizarse como tipos para la definición de tablas internas, estructuras y variables de los programas ABAP. Debemos utilizar el nombre que hemos especificado en el atributo sqlViewName y no el nombre de la vista ABAP CDS.

Consumición de la vista ABAP CDS 

COMO ENCONTRAR LAS VISTAS ABAP CDS CREADAS EN EL SISTEMA SAP

Consultando tabla TADIR, con los siguientes parámetros de selección, podemos encontrar todas las vistas CDS existentes en SAP, su nombre en el diccionario ABAP y el paquete al que pertenecen.

Acceder a la tabla TADIR con los siguientes parámetros:
  • PGMID = ‘R3TR’ 
  • OBJECT =’DDLS’ 
Accediendo la tabla DDLDEPENDENCY podemos obtener los nombres de la vista en el diccionario ABAP y en SAP HANA. Acceder a la tabla DDLDEPENDENCY con el parámetro:

  • OBJECTTYPE = 'VIEW'



Entradas de la tabla TADIR correspondientes a vistas CDS

Nombre de la vista ABAP CDS en HANA y en el diccionario ABAP


Fuente:

jueves, 6 de octubre de 2016

Misión Cumplida!!!

Los nervios casi me destrozan, pero misión completada!! Termine mi Máster universitario en investigación en ingeniería de software y sistemas informáticos!! 


lunes, 3 de octubre de 2016

Defensa del trabajo de fin de Máster

Mañana me toca viajar a Madrid a defender mi TFM
"Generación automática de código ABAP para sistemas SAP R3"

Un trabajo con el que me he introducido en las arquitecturas dirigidas a modelos (MDA) y la creación de modelos que generen automáticamente el código utilizando Eclipse Modeling Tools y Acceleo.

...que nervios...



jueves, 2 de junio de 2016

Aun seguimos aqui

Perdón por la inactividad  del blog.

No he desaparecido. Y sí, voy a continuar escribiendo pero este año esta siendo complicado.
Es mi ultimo año de Master por la UNED y entre el máster y el trabajo me queda poco tiempo para encargarme del blog.

Lo dicho, perdonar la inactividad.
En breves volveremos.

Un saludo a todos.

miércoles, 9 de marzo de 2016

Clase CL_SALV_TABLE: Toolbar, pulsadores y funciones a medida - parte I

Hasta ahora,  hemos explicado como mostrar la información que extraemos de la base de datos y como modificar los atributos de la columnas del listado ALV. Pero los usuarios, rara vez solamente quieren "ver" la información, lo normal es que quieran interactuar con ella de diferentes formas. Por ejemplo ordenar el listado, imprimir el listado descargar el listado  en una hoja excel, etc...

Para añadir funcionalidades a medida a los listados ALV, la CL_SALV_TABLE incluye pulsadores y funciones estándar que podemos configurar  antes de llamar al método display( ) .

try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).

      gr_table->get_functions( )->set_all( if_salv_c_bool_sap=>true ).     "TODOS los pulsadores estandard
*     gr_table->get_functions( )->set_default( if_salv_c_bool_sap=>true ). "Solamente algunos puls estandard

      gr_table->display( ).

    catch cx_salv_msg into cx_salv.
*     Gestionamos las excepciones que puedan suceder
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
    catch  cx_salv_not_found into cx_not_found.
      gr_msg = cx_not_found->get_text( ).
      message gr_msg type 'E'
  endtry.

Toolbar estándar creada con el metodo set_all( if_salv_c_bool_sap=>true )

Toolbar estándar creada con el metodo set_default( if_salv_c_bool_sap=>true )

Tambien es posible añadir pulsadores personalizados que llamen a  funciones diseñadas para propósitos específicos.

Para crear vuestro propio status de usuario, podeios copiar el status SALV_STANDARD del programa SALV_DEMO_METADATA desde la trnasacción SE38

  1. Transacción  SE38 -> SALV_DEMO_METADATA  -> Status GUI -> SALV_STANDARD
  2. Situar el cursor sobre Status GUI -> SALV_STANDARD
  3. Pulsar el botón derecho del ratón -> Copiar
  4. Introducimos el nombre de nuestro programa y el nuevo nombre del status gui
  5. En la copia que hemos realizado, añadir los pulsadores a medida que necesitamos.
  6. Vincular el STATUS GUI al ALV utilizando el método set_screen_status( ).
  7. Activarlo todo
try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).

      gr_table->set_screen_status( pfstatus = 'ZZSTATUS_001'  "Nuestro STATUS GUI
                                   report = sy-repid
                                   set_functions = gr_table->c_functions_all ).

      gr_table->display( ).

    catch cx_salv_msg into cx_salv.
*     Gestionamos las excepciones que puedan suceder
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
    catch  cx_salv_not_found into cx_not_found.
      gr_msg = cx_not_found->get_text( ).
      message gr_msg type 'E'
  endtry.

Si activamos y ejecutamos, aparecerán los pulsadores de nuestro status gui. Pero si los pulsamos, no sucederá nada. Para asignar una función a un pulsador, primero  necesitamos implementar una clase de eventos y enlazarla a nuestra clase CL_SALV_TABLE.

1.- Crear la siguiente definición para la clase de eventos CLASS_HANDLE_EVENTS. En este caso, solamente implementamos el evento ON_USER_COMMAND, pero se pueden implementar mas eventos que explicare en otra entrada.

*---------------------------------------------------------------------*
*       CLASS class_handle_events DEFINITION
*---------------------------------------------------------------------*
*  define a local class for handling events of cl_salv_table
*---------------------------------------------------------------------*
class class_handle_events definition.
  public section.
    methods:
      on_user_command
                    for event added_function of cl_salv_events
        importing e_salv_function. "e_salv_function es como el OK_CODE de las dynpros

endclass.                    "lcl_handle_events DEFINITION


2.- Crear la  implementacion de la clase y el método ON_USER_COMMAND.
*---------------------------------------------------------------------*
*       CLASS lcl_handle_events IMPLEMENTATION
*---------------------------------------------------------------------*
* implement the events for handling the events of cl_salv_table
*---------------------------------------------------------------------*
class class_handle_events implementation.

  method on_user_command.

    case e_salv_function. "Contiene el cod. de funcion del pulsador seleccionado
      WHEN 'GO_VBELN'.  "mensaje por pantalla
        MESSAGE "Esto es una prueba, funcion GO_VBELN" display like 'I'.
    ENDCASE.
  endmethod.

endclass.                    "lcl_handle_events IMPLEMENTATION


3.- El ultimo paso es enlazar la clase de eventos con nuestra instancia de la clase CL_SALV_TABLES. Esto significa que cuando se produzca un evento ( doble click, pulsar un boton de la barra de herramientas, etc...) sera "escuchado" por la clase de eventos y ejecutara el metodo asignado al evento.

Como podéis observar el parámetro de entrada e_alv_funcion contiene el código de función del pulsador que ha seleccionado el usuario en la barra de herramientas. Identificando ese código en el método ON_USER_COMMAND podemos identificar, procesar y actuar en función de la acción realizada por del usuario ( por ejemplo grabar los datos, ejecutar una bapi, salir del programa, etc...).

Todo evento que queráis en vuestro ALV tenéis que enlazarlo con la clase CL_SALV_TABLES:

DATA r_handler_salv_table type REF TO class_handle_events. 
try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).

      gr_table->set_screen_status( pfstatus = 'ZZSTATUS_001'  "Nuestro STATUS GUI
                                    report = sy-repid
                                    set_functions = gr_table->c_functions_all ).

*     Creamos la instancia de la clase de eventos y registramos el evento on_user_command
      CREATE OBJECT r_handler_salv_table.
      set handler r_handler_salv_table->on_user_command for gr_table->get_event( ).

      gr_table->display( ).

    catch cx_salv_msg into cx_salv.
*     Gestionamos las excepciones que puedan suceder
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
    catch  cx_salv_not_found into cx_not_found.
      gr_msg = cx_not_found->get_text( ).
      message gr_msg type 'E'
  endtry.


Aquí os dejo un ejemplo completo,  Es un listado de materiales, con pulsadores a medida.
No os olvidéis de crear el status gui y añadirle los pulsadores a medida
En la siguiente entrada os mostrare como añadir pulsadores y menús a la barra de herramientas utilizando eventos.

STATUS GUI de nuestro ALV
CL_SALV_TABLE con pulsadores a medida


*&---------------------------------------------------------------------*
*& Report:  ZZCL_SALV_TABLE_FULL_SCREEN
*& Autor :  David Rueda Barrón
*&---------------------------------------------------------------------*
*& Creacion de ALV a pantalla completa con la clase CL_SALV_TABLE
*& Se añaden 3 pulsadores a medida con un STATUS GUI
*& La clase de eventos CLASS_HANDLE_EVENTS recoje los eventos
*&---------------------------------------------------------------------*

report zzcl_salv_table_full_screen.

*---------------------------------------------------------------------*
*       CLASS class_handle_events DEFINITION
*---------------------------------------------------------------------*
*  define a local class for handling events of cl_salv_table
*---------------------------------------------------------------------*
class class_handle_events definition.
  public section.
    methods:
      on_user_command
                    for event added_function of cl_salv_events
        importing e_salv_function. "e_salv_function es como el OK_CODE de las dynpros

endclass.                    "lcl_handle_events DEFINITION
*---------------------------------------------------------------------*
*       CLASS lcl_handle_events IMPLEMENTATION
*---------------------------------------------------------------------*
* implement the events for handling the events of cl_salv_table
*---------------------------------------------------------------------*
class class_handle_events implementation.

  method on_user_command.

    case e_salv_function. "Contiene el cod. de funcion del pulsador seleccionado
      WHEN 'GO_VBELN'.  "mensaje por pantalla
        MESSAGE 'Esto es una prueba, funcion GO_VBELN' TYPE 'I'.
      WHEN 'GO_VF03'.
        MESSAGE 'Esto es una prueba, funcion GO_VF03' TYPE 'I'.
      WHEN 'GO_MM02'.
        MESSAGE 'Esto es una prueba, funcion MM02' TYPE 'I'.
    ENDCASE.

  endmethod.

endclass.                    "lcl_handle_events IMPLEMENTATION

*---------------------------------------------------------------------*
*       TIPOS, ESTRUCTURAS y VARIABLES GLOBALES
*---------------------------------------------------------------------*
types: begin of type_matnr,
         matnr type mara-matnr,
         maktx type makt-maktx,
         mtart type mara-mtart,
         matkl type mara-matkl,
         meins type mara-meins,
       end of type_matnr.

* Tabla interna con los datos del ALV
data ti_mara type standard table of type_matnr.


data gr_table type ref to cl_salv_table.
data r_handler_salv_table type REF TO class_handle_events.

*Variables globales para gestionar las excepciones
data gr_msg  type string.
data cx_salv  type ref to cx_salv_msg.
data cx_not_found TYPE ref to cx_salv_not_found.
*&---------------------------------------------------------------------*
*& START-OF-SELECTION
*&---------------------------------------------------------------------*
start-of-selection.

  select m~matnr t~maktx m~mtart m~matkl m~meins
    into corresponding fields of table ti_mara
    from mara as m
    inner join makt as t
       on m~matnr eq t~matnr
      and t~spras eq sy-langu.

  try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).
    catch cx_salv_msg into cx_salv.
*     Gestionamos las excepciones que puedan suceder
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
  endtry.

  try.
*   Registramos el status gui para el ALV
    gr_table->set_screen_status( pfstatus = 'ZZSTATUS_001'  "Nuestro STATUS GUI
                                 report = sy-repid
                                 set_functions = gr_table->C_FUNCTIONS_ALL ).

*   Creamos la instancia de la clase de eventos y registramos el evento on_user_command
    CREATE OBJECT r_handler_salv_table.
    SET HANDLER r_handler_salv_table->on_user_command for gr_table->get_event( ).

    catch  cx_salv_msg into cx_salv.
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
    catch  cx_salv_not_found into cx_not_found.
       gr_msg = cx_not_found->get_text( ).
      message gr_msg type 'E'.
  endtry.

  gr_table->display( ).

Entradas anteriores:

Entradas siguientes:
Clase CL_SALV_TABLE: Toolbar, pulsadores y funciones a medida - parte II

domingo, 27 de septiembre de 2015

Clase CL_SALV_TABLE: Modificar atributos de las columnas

En el anterior post mostramos como generar un ALV utilizando solo la clase CL_SALV_TABLE. A continuación vamos a explicar como se modifican los atributos de las columnas del ALV cuando lo generamos utilizando la clase CL_SALV_TABLE.

A diferencia de los ALV generados con la bapi REUSE_ALV_GRID_DISPLAY o con la clase CL_GUI_ALV_GRID  la clase  CL_SALV_TABLE no utiliza un catalogo de campos o fieldcat para determinar las características de las columnas del listado ALV.  Cada columna del ALV debe ser tratada como un objeto individual con métodos que nos permitirán modificar sus atributos y  características como su descripción, longitud, ocultar la columna, etc...

Necesitamos instanciar dos clases:
  • CL_SALV_COLUMNS_TABLE  : Gestionar las columnas que componen el ALV
  • CL_SALV_COLUMN    : Gestionar los atributos de una columna del ALV
La primera clase CL_SALV_COLUMNS_TABLE nos permitirá gestionar atributos y características de las columnas del ALV. Para mas información podéis acceder a los métodos y atributos de la clase CL_SALV_COLUMNS_TABLE desde la transacción SE24 -> Pasar a -> Documentación -> Clase.

Transacción SE24 -> Clase CL_SALV_COLUMNS_TABLE

Para modificar las características y atributos propios de cada columna del ALV  instanciaremos un objeto CL_SALV_COLUMN_TABLE utilizando el metodo GET_COLUMN de la clase CL_SALV_COLUMNS_TABLE. Este método recibe como parámetro de entrada el nombre de una columna del ALV y retorna un objeto de la clase CL_SALV_COLUMN_TABLE que nos permite con sus métodos cambiar las características y atributos de la columna.

Transacción SE24 -> Clase CL_SALV_COLUMN_TABLE

Desde la transacción SE24  -> Pasar a -> Documentación -> Clase  podéis ver todos los métodos de la clase CL_SALV_COLUMN y que atributos nos permiten modificar.  Los métodos que mas se suelen utiliza son:


  • SET_LONG_TEXT:  Descripción larga de la columna
  • SET_MEDIUM_TEXT:Descripción media de la columna
  • SET_SHORT_TEXT: Descripción corta de la columna
  • SET_VISIBLE:   Oculta o muestra la columna ( 'X' muestra , '  '  oculta la columna )
  • SET_OUTPUT_LENGTH:  Especifica el ancho de la columna 
  • SET_OPTIMIZED:  Optimiza el ancho de la columna automáticamente
  • SET_CELL_TYPE: formato de la celda ( ej: campo, checkbox, etc.. ) 

A continuación, ampliamos el código del anterior post para modificar las características de algunas columnas.


*&---------------------------------------------------------------------*
*& Report:  ZZCL_SALV_TABLE_FULL_SCREEN
*& Fecha :  29.07.2015
*& Autor :  David Rueda Barrón
*&---------------------------------------------------------------------*
*& Creacion de ALV a pantalla completa con la clase CL_SALV_TABLE
*& Modificacion de los atributos de la columnas con las clases:
*&   - CL_SALV_COLUMNS_TABLE
*&   - CL_SALV_COLUMN_TABLE
*&---------------------------------------------------------------------*

report zzcl_salv_table_full_screen.

types: begin of type_matnr,
         matnr type mara-matnr,
         maktx type makt-maktx,
         mtart type mara-mtart,
         matkl type mara-matkl,
         meins type mara-meins,
         box   type c,
       end of type_matnr.

data: ti_mara type standard table of type_matnr.

data gr_table     type ref to cl_salv_table.         "Instancia de la clase
data gr_columns   type ref to cl_salv_columns_table. "Para gestionar las columnas
data gr_column    type ref to cl_salv_column_table.  "Para gestionar atrb. de una columna
data cx_salv      type ref to cx_salv_msg.
data cx_not_found TYPE ref to cx_salv_not_found.

data gr_msg  type string.
*&---------------------------------------------------------------------*
*& START-OF-SELECTION
*&---------------------------------------------------------------------*
start-of-selection.

  select m~matnr t~maktx m~mtart m~matkl m~meins
    into corresponding fields of table ti_mara
    from mara as m
    inner join makt as t
       on m~matnr eq t~matnr
      and t~spras eq sy-langu.

  try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).
    catch cx_salv_msg into cx_salv.
*     Gestionamos las excepciones que puedan suceder
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
  endtry.

  try.
      gr_columns ?= gr_table->get_columns( ).
*     gr_columns->set_optimize( 'X' ).   "Optimizar automa. abcho de TODAS las columnas

*     Cambiamos la descripción de la columna MATNR - MATERIAL
      gr_column  ?= gr_columns->get_column( 'MATNR' ).
      gr_column->set_short_text( 'Cod.Mat.' ).
      gr_column->set_medium_text( 'Cod. Material' ).
      gr_column->set_long_text( 'Código Material SAP' ).

*     Ocultamos la columna MTART - Tipo de material
      gr_column  ?= gr_columns->get_column( 'MTART' ).
      gr_column->set_visible( value  = if_salv_c_bool_sap=>false ).

*     Cambiamos la longitud de la columnas:
*     MAKTX descripción del material
*     MATKL Grupo de articulos
      gr_column  ?= gr_columns->get_column( 'MAKTX' ).
      gr_column->set_output_length( 30 ).

      gr_column  ?= gr_columns->get_column( 'MATKL' ).
      gr_column->set_output_length( 20 ).

*     Cambiamos la descripcion y formato de la columna box
      gr_column  ?= gr_columns->get_column( 'BOX' ).
      gr_column->set_short_text( 'box' ).
      gr_column->set_medium_text( 'Checkbox' ).
      gr_column->set_long_text( 'Checkbox' ).
      gr_column->set_cell_type( if_salv_c_cell_type=>checkbox ).

    catch  cx_salv_msg into cx_salv.
      gr_msg = cx_salv->get_text( ).
      message gr_msg type 'E'.
    catch  cx_salv_not_found into cx_not_found.
       gr_msg = cx_not_found->get_text( ).
      message gr_msg type 'E'.
  endtry.

  gr_table->display( ).

CL_SALV_TABLE  con los atributos de las comunas modificados

Entradas anteriores:
Clase CL_SALV_TABLE: Introducción

jueves, 30 de julio de 2015

Clase CL_SALV_TABLE: Introducción

La clase CL_SALV_TABLE es una aproximación  basada  en el paradigma de la programación orienta objetos para el desarrollo de listados ALV en aplicaciones SAP. La clase CL_SALV_TABLE forma parte del modelo basado en objetos para ALV ( ALV Object Model ) que agrupa diferentes clases globales para la implementación de listados ALV y que esta  incluido a partir de la versión 6.40 de SAP.

CL_SALV_TABLE se utiliza para crear listados ALV de dos dimensiones y con un estilo de hoja de calculo de forma fácil y rápida en nuestras aplicaciones ABAP.

La única limitación de esta clase es que no existe ningún  método para crear ALV editables.

Para crear la instancia de la clase CL_SALV_TABLE invocamos a su método FACTORY.
Una vez creado, para mostrar por pantalla el ALV por primera vez invocamos el método DISPLAY
Para refrescar los datos del ALV en la pantalla, invocamos al método REFRESH

Podeis visualizar sus atributos y métodos desde la transacción SE24.

Clase global CL_SALV_TABLE

CL_SALV_TABLE a pantalla completa:
En el siguiente ejemplo, implementamos un ALV a pantalla completa utilizando la clase CL_SALV_TABLE.

*&---------------------------------------------------------------------*
*& Report:  ZZCL_SALV_TABLE_FULL_SCREEN
*& Fecha :  29.07.2015
*& Autor :  David Rueda Barrón
*&---------------------------------------------------------------------*
*& Creacion de ALV a pantalla completa con la clase CL_SALV_TABLE
*&---------------------------------------------------------------------*

REPORT ZZCL_SALV_TABLE_FULL_SCREEN.

TYPES: BEGIN OF type_matnr,
  matnr type mara-matnr,
  maktx type makt-maktx,
  MTART type mara-MTART,
  MATKL type mara-matkl,
  MEINS type mara-MEINS,
 END OF type_matnr.

DATA: ti_mara type STANDARD TABLE OF type_matnr.

DATA gr_table type ref to cl_salv_table.  "instancia de la clase
DATA cx_salv  TYPE REF TO cx_salv_msg.

DATA gr_msg  TYPE string.
*&---------------------------------------------------------------------*
*& START-OF-SELECTION
*&---------------------------------------------------------------------*
START-OF-SELECTION.

SELECT m~matnr t~maktx m~mtart m~matkl m~meins
  INTO CORRESPONDING FIELDS OF TABLE ti_mara
  FROM mara as m
  INNER JOIN makt as t
     ON m~matnr EQ t~matnr
    AND t~spras EQ sy-langu.

try.
      cl_salv_table=>factory(
        importing
          r_salv_table = gr_table
        changing
          t_table      = ti_mara ).
catch cx_salv_msg INTO cx_salv.
* gestionamos las excepciones que puedan suceder
  gr_msg = cx_salv->get_text( ).
  MESSAGE gr_msg TYPE 'E'.
endtry.

gr_table->display( ).

CL_SALV_TABLE a pantalla completa

CL_SALV_TABLE dentro de una dynpro:
En el siguiente ejemplo, implementamos un ALV dentro de un objeto contenedor para que pueda ser visualizado en una  dynpro de una aplicación ABAP de tipo modul pool.

Como hemos comentado, en este caso, el ALV va ha estar contenido en una dynpro.
El programa principal se encargara  de rellenar la tabla interna y llamar a la dynpro.


*&---------------------------------------------------------------------*
*& Report:  ZZCL_SALV_TABLE_DYNPRO
*& Fecha :  29.07.2015
*& Autor :  David Rueda Barrón
*&---------------------------------------------------------------------*
*& Creación de ALV dentro de Dynpro con la clase CL_SALV_TABLE
DATA ti_mara type STANDARD TABLE OF type_matnr.
*&---------------------------------------------------------------------* REPORT ZZCL_SALV_TABLE_DYNPRO. TYPES: BEGIN OF type_matnr, matnr type mara-matnr, maktx type makt-maktx, MTART type mara-MTART, MATKL type mara-matkl, MEINS type mara-MEINS, END OF type_matnr.
DATA ok_code type sy-ucomm. 

DATA gr_table     TYPE REF TO cl_salv_table.  "instancia de la clase
DATA gr_container TYPE REF TO cl_gui_custom_container.

DATA cx_salv  TYPE REF TO cx_salv_msg.

DATA gr_msg  TYPE string.
*&---------------------------------------------------------------------*
*& START-OF-SELECTION
*&---------------------------------------------------------------------*
START-OF-SELECTION.

SELECT m~matnr t~maktx m~mtart m~matkl m~meins
  INTO CORRESPONDING FIELDS OF TABLE ti_mara
  FROM mara as m
  INNER JOIN makt as t
     ON m~matnr EQ t~matnr
    AND t~spras EQ sy-langu.

CALL SCREEN 4001.


Para crear la dynpro, tenéis que hacer doble click sobre el número de dynpro 4001.

Doble click sobre el número de dynpro para crearla

Como cualquier dynpro, lo primero es introducir una descripción, el resto de campos los dejamos como están, no hace falta modificarlos para esta prueba .

descripción de la dynpro

En la pestaña Lista Elementos, escribimos OK_CODE  en la única celda que hay editable.
Nota: OK_CODE es una variable global del programa principal de tipo SY-UCOMM.

OK_CODE para recoger el código de función de cada evento de la dynpro

Después hay que implementar los módulos STATUS y USER_COMMAND en la pestaña Lóg. proceso.

   1. Descomentamos la linea de MODULE STATUS_4001
   2. Doble click sobre nombre del modulo STATUS_4001 para crearlo.
   3. Guardamos el nuevo modulo en el include ZZCL_SALV_TABLE_DYNPRO_PBO
Crear el Modulo STATUS_4001
 
   4. Descomentamos la linea de código que empieza por SET_STATUS....
   5. Sustituimos las  XXXXXXX  por el nombre de nuestro status, por ejemplo: ZZSTATUS_4001
   6. Doble click sobre el nombre del status y creamos un nuevo Status diálogo.
   7. Desplegar la sección Teclas de función.
   8. En los siguientes iconos, escribimos los siguientes códigos de funciones:


Códigos de funciones para el status de la dynpro 4001

Lo siguiente es implementar el modulo USER_COMMAND_4001:

   1. Descomentamos la instrucción MODULE USER_COMMAND_4001.
   2. Doble click sobre nombre del modulo USER_COMMAND_4001 para crearlo.
   3. Guardamos el nuevo modulo en el include ZZCL_SALV_TABLE_DYNPRO_PAI

Crear el modulo USER_COMMAND_4001
   4. Dentro del modulo USER_COMMAND_4001 colocamos el siguiente código:

DATA wl_command TYPE sy-ucomm.

wl_command = ok_code.
clear ok_code.

CASE wl_command.
   WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
      SET SCREEN 0.
      LEAVE SCREEN.
ENDCASE.

Activamos todos los includes , la dynpro 4001 y el status ZZSTATUS_4001.
Con esto ya tenemos creada una dynpro y las funcione para poder cerrarla.

Ahora toca incrustar en ella nuestro ALV de la clase CL_SALV_TABLE.

   1. Volvemos ala dynpro 4001 y pulsamos el boton LAYOUT en la barra de herramientas.
   2. Dibujamos un objeto contenedor en la dypro, le damos el nombre de ZCONTENEDOR_ALV.
   3. Activamos y cerramos el editor de Dynpros

Añadimos un contenedor a la dynpro 4001

   4.Creamos un nuevo modulo en la sección PROCESS BEFORE OUTPUT de la dynpro 4001.
      Guardamos el modulo en el include ZZCL_SALV_TABLE_DYNPRO_PBO
     
nuevo modulo PBO - SET_ALV
   5. Incluimos el siguiente código dentro del modulo:

if ( gr_container is not bound ).
*   Si es la primera vez, instancia las clases y muestra los datos de la tabla
    create object gr_container
      exporting
        container_name              = 'ZCONTENEDOR_ALV'
      exceptions
        cntl_error                  = 1
        cntl_system_error           = 2
        create_error                = 3
        lifetime_error              = 4
        lifetime_dynpro_dynpro_link = 5
        others                      = 6.

    if ( sy-subrc <> 0 ).
      message id sy-msgid type sy-msgty number sy-msgno
                 with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endif.

    cl_salv_table=>factory(
             exporting
                 r_container    = gr_container
                 list_display   = ' '
               importing
                 r_salv_table   = gr_table
               changing
                 t_table        = ti_mara ).

    gr_table->display( ).
  else.
*   Si ya estan instanciadas las clases, pues refrescamso los datos de la pantalla
    gr_table->refresh( ).
  endif.


Activamos todos los includes, dynpros y status.
Ejecutamos para ver el resultado

ALV con CL_SALV_TABLE dentro de una dynpro


En resumen, la clase CL_SALV_TABLE reduce el código que necesitamos para crear listados ALV por pantalla pero no podemos crear ALV editables..

Entradas siguientes:
Clase CL_SALV_TABLE: Modificar atributos de las columnas