Usando Table Functions y Vistas CDS

Al igual que cuando creamos la vista CDS, para crear una table function debemos crear un data definition como hicimos antes, pero al momento de llegar al template seleccionamos “Define Table Function with parameters”

Al hacer click en finish nos aparecerá el template seleccionado el cual debemos completar para que quede similar a lo siguiente:

@EndUserText.label: 'Table function para vuelos'
define table function ZTF_VUELOS
with parameters 
@Environment.systemField: #CLIENT
client : mandt,
returns {
  client : abap.clnt;
  carrid : s_carr_id;
  connid : s_conn_id;
  fldate : s_date;
  carrname : s_carrname;
  URL : s_carrurl;
  price : s_price;
  currency : s_currcode;
  passname : s_passname;
}
implemented by method zcl_vuelos2=>obtener_datos_pasajeros;

Vemos que al final le estamos especificando la clase (ZCL_VUELOS2) y el método (obtener_datos_pasajeros) que vamos a llamar.

El próximo paso será crear esta clase y método, para esto hacemos click derecho sobre nuestro package o objeto local y seleccionamos crear una clase.

Ingresamos un nombre (El que usamos en la Table function) y descripción.

De nuevo seleccionamos una orden de transporte y le damos click a Finish o si es un objeto local directamente hacemos click en finish.

Nos creara el template que se vera similar a:

Adaptamos la clase para que tenga la lógica que nosotros queramos, por ejemplo:

CLASS zcl_vuelos2 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES : if_amdp_marker_hdb.
    CLASS-METHODS :  obtener_datos_pasajeros FOR TABLE FUNCTION ZTF_VUELOS.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_vuelos2 IMPLEMENTATION.

        METHOD obtener_datos_pasajeros BY DATABASE FUNCTION FOR HDB
                        LANGUAGE SQLSCRIPT
                        OPTIONS READ-ONLY
                        USING scarr sflight sbook.

               RETURN

                    SELECT a.mandt AS client, a.carrid AS carrid, a.connid AS connid, a.fldate AS fldate,
                           b.carrname AS carrname, b.URL as URL, a.price AS price, a.currency AS currency,
                           c.passname AS passname FROM sflight AS a
                           INNER JOIN scarr AS b
                            ON a.carrid = b.carrid
                           INNER JOIN sbook AS c
                            ON a.carrid = c.carrid AND
                               a.connid = c.connid AND
                               a.fldate = c.fldate
                           WHERE a.mandt = c.mandt;
        ENDMETHOD.
ENDCLASS.

Ahora debemos creamos una vista CDS que utilice nuestra table function. Para esto, como hicimos antes nos creamos una vista CDS.

Nuestra vista debería ser algo similar a esto:

Lo importante a ver acá, es que estamos haciendo el SELECT desde la Table Function (SELECT FROM ZTF_VUELOS ).

@AbapCatalog.sqlViewName: 'ZCDS_TF_DATOS_V'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Datos de pasajeros usando TF'
define view ZCDS_TF_DATOS as select from ZTF_VUELOS ( client : $session.client ) {
    carrid,
    connid,
    fldate,
    carrname,
    URL,
    @Semantics.amount.currencyCode: 'CurrencyCode' 
    price,
    @Semantics.currencyCode
      cast ('USD' as abap.cuky) as CurrencyCode,
    currency,
    passname
}

Una ves con nuestra nueva vista creada, la podemos consultar como hicimos antes desde la SE16. Pero también lo que podemos hacer es ponerle un breakpoint en la clase que creamos.

Para hacer esto, en eclipse, vamos a la clase que creamos y hacemos doble click donde esta marcado en la captura de abajo. Nos debería aparecer un puntito en color verde si el breakpoint esta activo.

Una ves con el breakpoint activo, podemos ejecutar la vista desde la SE16 y se nos debería activar el debugger en eclipse.

Para ver mejor por debug podemos cambiar el código por:

CLASS zcl_vuelos2 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES : if_amdp_marker_hdb.
    CLASS-METHODS :  obtener_datos_pasajeros FOR TABLE FUNCTION ZTF_VUELOS.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_vuelos2 IMPLEMENTATION.

        METHOD obtener_datos_pasajeros BY DATABASE FUNCTION FOR HDB
                        LANGUAGE SQLSCRIPT
                        OPTIONS READ-ONLY
                        USING scarr sflight sbook.

/*               RETURN */

                    lt_datos = SELECT a.mandt AS client, a.carrid AS carrid, a.connid AS connid, a.fldate AS fldate,
                           b.carrname AS carrname, b.URL as URL, a.price AS price, a.currency AS currency,
                           c.passname AS passname FROM sflight AS a
                           INNER JOIN scarr AS b
                            ON a.carrid = b.carrid
                           INNER JOIN sbook AS c
                            ON a.carrid = c.carrid AND
                               a.connid = c.connid AND
                               a.fldate = c.fldate
                           WHERE a.mandt = c.mandt;

                    RETURN :lt_datos;

        ENDMETHOD.
ENDCLASS.

En la imagen de abajo podemos ver el breakpoint en la línea 22, a la derecha del código podemos ver nuestra variable lt_datos donde se guarda el resultado de la consulta y en la parte de inferior de la pantalla podemos ver el contenido de la tabla interna.

Tambien al igual que con una vista CDS común, la podemos usar desde un reporte ABAP:

SELECT * FROM ZCDS_TF_DATOS( pcarrid = 'AA', pconnid = '0017', pfldate = @lv_fecha )
  INTO TABLE @DATA(lt_datos2).
IF sy-subrc = 0.

ENDIF.

Tambien podemos usar un ALV IDA para mostrar los datos:

REPORT zida_cds.
data: lo_exc type ref to cx_salv_function_not_supported.

try.
  cl_salv_gui_table_ida=>create_for_cds_view( 'ZCDS_VUELOS' )->fullscreen( )->display( ).
  catch cx_salv_function_not_supported into lo_exc.
    message lo_exc type 'I'.
endtry.

Clases ABAP (Globales)

En SAP hay dos tipos de clases, las que podemos desarrollar en un reporte Z, como vimos en el post anterior, o las clases globales que son las que definimos en la transacción SE24.

La principal diferencia entre una clase global y una local es que las locales son especificas a un reporte, mientras las clases globales pueden ser usadas desde cualquier lado.

Para definir una clase, vamos a la transacción SE24, para seguir con el ejemplo anterior vamos a volver a crear la clase vehículo.

Hacemos click en “Create”

En la siguiente ventana ingresamos una descripción y hacemos click en “SAVE”

Creamos el objeto como un objeto local.

Nos aparecerá la siguiente ventana donde debemos especificar el método a crear, visibilidad, tipo, etc.

El siguiente paso es definir los parámetros de los métodos, para eso seleccionamos un método y hacemos click en el botón “Parameters”.

Vamos a la solapa “Attributes” y definimos nuestra variable protegida.

Con nuestra clase con los métodos y variable definidas le damos click a activar.

Nos aparecerá una ventana como la siguiente en donde seleccionamos todos los objetos y le damos OK.

Nuestra clase debería haber quedado activa.

Finalmente hay que hacer el código que en cada método para que la clase haga algo.

Metodo obtener tipo:

WRITE 'AUTO'.

Método obtener marca:

WRITE 'FORD'.

Método set_notas:

lv_notas = notas.

Método ver_notas:

notas = lv_notas.

En este punto ya tenemos nuestra clase lista, solo nos resta volver a activarla para asegurarnos que esta todo OK.

Ahora nuestra clase estará disponible para ser usada desde cualquier reporte que se quiera crear.

Abajo dejo un ejemplo de uso.

*&---------------------------------------------------------------------*
*& Report Z_CLASE_GLOBAL
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT Z_CLASE_GLOBAL.

DATA: lc_cg TYPE REF TO ZCL_VEHICULO.

CREATE OBJECT lc_cg.

lc_cg->set_notas( 'Una nota' ).
lc_cg->obtener_tipo( ).
NEW-LINE.
lc_cg->obtener_marca( ).
NEW-LINE.

DATA: lv_notas TYPE string.
lc_cg->ver_notas( IMPORTING notas = lv_notas ).
WRITE lv_notas.