You are on page 1of 551

Para mi esposa Milly y

mi hija Tammy Luz.

Sobre el Autor…

Alvaro Tejada Galindo se inició en el mundo de la
programación a los 20 años. Sus primeros lenguajes
fueron C++ y Visual Basic 6.0 lo cuales aprendió de
manera autodidacta gracias a libros, foros, tutoriales y
códigos fuente.
A lo largo de los años, fue agregando nuevos lenguajes a su
colección, tales como Java, QBasic, Pascal, Delphi, HTML y
JavaScript.
Fue cuando tenía 24 años, que conoció el mundo del SAP, puesto
que entró a hacer sus prácticas en TSNet Global, en donde trabajó
por espacio de 2 años, con grandes proyectos en empresas como
Telefónica del Perú, Carsa, Minsur, Alicorp y Funsur.
Luego de dejar TSNet Global (Consultora Peruana), se dio un
descanso para continuar estudiando y dedicarse al aprendizaje de
PHP. Luego de esto, trabajó durante 2 años en la Consultora
ActualiSap (Consultora Chilena), en donde además de dos exitosos
proyectos de implementación en Suez Enegy Perú y el Aeropuerto
Jorge Chávez, dictó un curso interno de IDoc’s en Santiago de Chile.
Tuvo un breve paso por Servisoft (Consultora Peruana) en el
proyecto de E. Wong. Con Stefanini IT Solutions trabajó para
Alicorp, Exsa, Votorantim Metais y el Banco de Crédito del Perú.

2

Su experiencia en SAP y ABAP es de 5 años a la fecha, en los
cuales siempre ha buscado obtener lo mejor del sistema.

Adicionalmente, es uno de los Bloggers o Columnistas del SAP
Developer Network o SDN (http://sdn.sap.com) en donde escribe
artículos sobre ABAP, HR, Integración de PHP con SAP e
Integración de Ruby con SAP.
Además, es Moderador en los foros del SDN y Mentor de SAP para
América Latina y el resto del mundo.
Pueden leer sus artículos en la siguiente dirección:

http://tinyurl.com/jnlfd
http://atejada.blogspot.com

3

Indice
Conociendo el entorno SAP NetWeaver 7
Introducción 7
Ingresando al sistema 8
Conociendo las transacciones más importantes 12
El Menú de SAP NetWeaver 21
Diccionario de Datos 23
Introducción 23
Elementos del Diccionario de Datos 23
Creando una tabla 26
Creando un dominio 37
Creando un elemento de datos 38
Creando una vista de actualización 50
Creando una ayuda de búsqueda 60
Creando una estructura 65
Creando una Vista 66
Programación en ABAP 70
Introducción 70
Estructura de un programa ABAP 71
Declaración de variables y tablas internas 78
Selección de datos 83
Lectura de datos en tablas internas 86
Operadores de comparación 89
Operaciones en tablas internas 98
Copiar tablas internas 104
Ordenar tablas internas 108
Estructuras de Control 110
Trabajando con Cadenas de Texto 111
Variables de Sistema 119
Modularización de programas 121
Depuración de programas 129
Programas de ejemplo 138
SapScript 159
Introducción 159
Creando un formulario 159
Crear una página principal 161

4

Crear ventana en página 163
Crear párrafo por defecto 166
Creando un programa de impresión 168
Diseñando el formulario 175
Ejecutando el formulario 182
Debugger en SAPScript 185
SmartForms 187
Introducción 187
Creando un estilo 187
Creando un formulario 191
Creando un programa de impresión 196
Ejecutando el formulario 200
Crear una tabla 202
Screen Painter y Menu Painter 210
Introducción 210
Screen Painter 210
Controles del Screen Painter 213
Ejemplo de Screen Painter 215
Menu Painter 228
Agregando componentes 235
Programación avanzada en Dynpros 240
MatchCodes dinámicos 240
Eliminar registros en un Table Control 246
Escritura/Lectura en un Table Control 249
Trabajando con subScreens 259
Utilizando listas desplegables 272
Leyendo datos de un Dynpro 278
Módulos de Función y BAPIS 280
Introducción Módulos de Función 280
Creando nuestra primera función 280
Llamando funciones desde un programa 288
Introducción BAPIS 290
ALV (ABAP List Viewer) 292
Introducción 292
Creando un ALV 292
Agregando una cabecera al reporte 301
Eventos ALV 308
Pintemos con colores 313
Barra de menú en ALV 320
ABAP Orientado a Objetos 328

5

Introducción 328
¿Qué es la Orientación a Objetos? 328
Conceptos básicos de POO 329
Como programar en ABAP Objects 335
Componentes Orientados a Objetos 351
Crear un ALV Grid OO 351
Agregar validaciones y eventos 365
Crear un ALV Tree OO 379
Agregar validaciones y eventos 399
Crear un ALV Object Model 409
Agregar validaciones y eventos 416
Cargar Imágenes en Dynpros 421
Leer PDF’s 430
Comprimir (zip) archivos 438
Crear un Control de Texto 451
WebDynpro 458
Introducción 458
Creando nuestro primer WebDynpro 458
BSP 489
Introducción 489
Creando nuestro primer BSP 489
ABAP y XML 501
Scripting in a Box 518
SAPLink 521
Integración PHP-NetWeaver 525
Introducción 525
Instalando el SAPRFC 526
Comunicándonos con NetWeaver 527
Integración Ruby-NetWeaver 539
Introducción 539
Instalando el SAP:Rfc 540
Comunicándonos con NetWeaver 540
Donde conseguir el SAP NetWeaver Sneak Preview 546
Bibliografía y agradecimientos 547
Enlaces Web 549

6

Conociendo el entorno SAP NetWeaver

Introducción

NetWeaver es la evolución del SAP R/3 que es un ERP (Enterprise
Resource Planning – Planificador de Recursos Empresariales).
¿Porque llamamos a NetWeaver una evolución del R/3? Pues porque
NetWeaver incorpora todos los aspectos de la programación orientada
a objetos, así como una fuerte integración web.
Al decir que se incorporan todos los aspectos de la programación
orientada a objetos, nos referimos a que el ABAP (Advanced Business
Application Programming) ha evolucionado también, proveyendo
herramientas de desarrollo que aumentan la productividad.
A lo largo de este libro, vamos a trabajar con SAP NetWeaver 7.0
Trial Version al que llamaremos NSP (NetWeaver Sneak Preview),
que no es más que una versión reducida del NetWeaver que nos
permite tomar ventaja de todos los componentes de desarrollo del
sistema.
Para poder tener un mejor aprendizaje de los conceptos que se
explican en el libro, vamos a crear dos tablas de base de datos muy
sencillas y las mismas serán utilizadas para todos los ejemplos.

7

Ingresando al Sistema

Para poder ingresar a NSP, deberemos contar con un usuario y
password, proporcionados por el administrador del sistema.
En nuestro caso, tenemos 2 usuarios que comparten un mismo
password.

• SAP* Æ Super Usuario. Con este usuario podemos crear
nuevos usuarios en NSP.
• BCUSER Æ Usuario Desarrollador. Con este usuario
podemos programar en NSP.
• DDIC Æ Usuario de Diccionario de Datos. Con este usuario,
podemos acceder a los datos almacenados dentro del NSP.

En esta pantalla podemos ver el SAP Logon, que es donde se
almacenan las entradas a los diferentes servidores de NSP.
En su caso, ustedes solamente van a tener uno, así que los marcan
(NSP Local) y presionamos Acceder al Sistema.

8

9

En esta ventana es donde ingresaremos nuestro usuario y password. En
la caja de texto de Language (Idioma), solamente podremos ingresar
EN Æ Inglés o DE Æ Alemán. El inglés es el idioma por defecto.
Luego de haber ingresado al sistema, veremos la pantalla principal del
NSP.

Esta es la pantalla de inicio, en donde podremos acceder a las
transacciones que nos ofrece NSP. Las transacciones son códigos
generalmente de 4 dígitos que sirven como accesos directos a los
programas que se ejecutan internamente en el NSP.
Para acceder, tenemos dos opciones, buscarlas en el menú del lado
izquierdo.

10

O escribir directamente la transacción a la cual queremos dirigirnos.

11

. Aquí podemos crear nuestro programas o includes (Programas no ejecutables que se incluyen dentro de programas ejecutables).Conociendo las transacciones más importantes 1. 12 .SE38 (Editor ABAP) Este es el entorno de programación del NSP.

visualizar o modificar Tablas.. Dominios. Estructuras y Ayudas para Búsqueda. 13 . Vistas.2.SE11 (Diccionario ABAP) En esta transacción podremos crear.

3. 14 ..SE16 (Browser de Datos) Es donde visualizamos los datos incluidos en Tablas o Vistas.

. 15 .4.SE71 (Form Painter) Nos permite crear formularios de Impresión.

Certificados. aunque depende de cada desarrollador. Por lo general se utilizan para generar Cartas de Pago a Bancos.Podemos definir páginas. insertar imágenes. ventanas. Se puede utilizar cualquiera de los dos. El SmartForms es la nueva versión del SapScript. Facturas. márgenes. tipos de párrafo. tabuladores. 16 . 5. Cheques.SmartForms (Form Painter Avanzado) Nos permite crear formularios de Impresión..

17 .6.SE51 (Screen Painter) Nos permite diseñar pantallas para crear programas interactivos..

SE41 (Menu Painter) 18 .7..

SE37 (Function Builder) Nos permite crear funciones para utilizar en nuestros programas. 19 .8.. así como modificar o visualizar funciones ya creadas.

20 .

Æ Grabar. contamos con una barra de menú.El menú de SAP NetWeaver En todas las transacciones. Æ Imprimir. Æ Retroceder una pantalla. Ej: /nSE38 ó /oSE16. Æ Aquí es donde se escribe la transacción a la cual queremos acceder. accederemos a ella en una nueva ventana. accederemos a ella en la misma ventana. 21 . Æ Buscar más. Si escribimos /o antes de la transacción. Æ Cancelar el programa o transacción. Æ Salir del programa o transacción. Æ Buscar. Veamos cuales son: Æ Equivale a hacer clic en la tecla Enter. que nos permite interactuar con las aplicaciones de NetWeaver. Si escribimos /n antes de la transacción.

Æ Se habilitan en Tablas y sirven para avanzar o retroceder registros. Æ Crea un acceso directo en el escritorio. Æ Configuraciones GUI. 22 . Æ Abre una nueva ventana o sesión del NetWeaver. Æ Ayuda.

es decir.. estructuras.. que en NetWeaver. es el repositorio en el cual se almacenan todas las tablas. todos los programas. Vamos a dar un breve repaso de todos los conceptos que intervienen en el diccionario de datos. Cabe destacar.Y eso que hablamos de la versión Sneak Preview.Tablas Las tablas se dividen en 3 tipos básicos: • Tablas Transparentes (Transparent Tables): Posee una relación de uno a uno con una tabla de la Base de Datos.. 23 . dominios. NetWeaver cuenta con 63. cada tabla transparente definida en el Diccionario de Datos. existe físicamente en la base de datos. ayudas de búsqueda. includes y elementos del diccionario son almacenados en tablas. Elementos del Diccionario de Datos 1.Diccionario de Datos Introducción El Diccionario de Datos en NetWeaver. así como la manera de crear cada uno de sus diferentes componentes. Es el tipo más común de tabla y es el más utilizado por los desarrolladores ABAP. Por lo tanto. Es decir. todo es manejado por tablas. la versión real del NetWeaver debe tener por lo menos el doble o triple de tablas. funciones. elementos de datos.348 tablas standard.

• Tablas Reunidas (Pooled Tables): Posee una relación de muchos a uno con una tabla de la Base de Datos. Este tipo de tablas.. como las tablas del sistema. • Tablas Racimo (Cluster Tables): Una tabla racimo.Componentes de una tabla Las tablas están compuestas por campos. existen muchas tablas en el Diccionario de Datos. Poseen una relación de muchos a uno con una tabla de la Base de Datos. tales como su longitud y su tipo de dato. y cada campo debe de estar asignado a un Elemento de Datos o a un Tipo Predefinido. Una definición de Elementos de Datos. Muchas tablas racimo son almacenadas físicamente en la Base de Datos en tablas llamadas Table Cluster. Este tipo de tablas son definidas por SAP y su uso se limita a tablas que son accedidas constantemente. 2. requiere a su vez de un Dominio. Los Elementos de Datos. contienen las características técnicas de un campo. se encuentran almacenadas físicamente en la Base de Datos en tablas llamadas Pool Tables. por una tabla que existe físicamente en la base de datos. es similar a una Pool Table. son definidas por SAP. Los Dominios. contienen los nombres del campo. así como también almacenan los valores de la ayuda en línea. Muchas tablas Pool. 24 . Es decir.

Creación de Objetos del Diccionario Para acceder al Diccionario de Datos. Tipos de Datos para Dominios Tanto los Elementos de Datos como los Dominios. deberemos ingresar a la transacción SE11. 25 . son reutilizables. Lo que significa que pueden estar definidos en más de una tabla. sin que esto genere algún tipo de conflicto.

vamos a crear 2 tablas.Creando una tabla Para propósitos del libro.. modificar. Con estas 26 . eliminar o crear los siguientes elementos: • Tablas Transparentes • Vistas • Estructuras • Dominios • Elementos de Datos • Ayudas para búsqueda 1.En esta transacción podremos visualizar. llamadas ZLENGUAJES_PROG y ZENTORNOS_PROG.

vamos a trabajar todos los ejemplos del libro. 27 . Para crear nuestra primera tabla. además de una clase de entrega y definir si la tabla puede ser mantenida desde la transacción SE16 o por algún programa externo. deberemos ingresar una descripción para la tabla. hacemos lo siguiente: • Escribimos el nombre de la tabla que queremos crear. así que es muy importante que las creen para poder seguir los ejemplos con mayor facilidad. puesto que es la única restricción que nos da NetWeaver al momento de crear cualquier elemento o componente. se nos presenta una ventana. en la cual. Como se habrán dado cuenta. • Presionamos el botón Create.tablas. ambas tablas comienzan con el prefijo “Z”. En este momento.

También debemos escoger el tipo de Mantenimiento que se le va a dar a la tabla. En nuestro caso. En todo caso. Tenemos dos opciones. escogeremos la opción Display/Maintenance Allowed para poder generar una Vista de Actualización más adelante. Clase de Entrega Casi en un 99% de las veces. Cuando grabemos. nos pide asociar nuestra tabla a un Package (Paquete). son los tipo C y L. la única que podríamos utilizar además de esta. que nos es más que una tabla donde se organizan los desarrollos por tipos. nos encontraremos con una ventana muy común en NetWeaver. o 28 . así que es la que vamos a utilizar nosotros. se utiliza la clase de entrega A. Esta ventana.

Y escogemos la opción Package de la lista. vamos a crear nuestro propio Package. o podemos crear nuestro propio Package en donde almacenaremos todos los componentes que creemos en el libro. • Con un clic derecho. así que debemos hacer lo siguiente: • Abrimos una nueva ventana o sesión con /oSE80 (Object Navigator).utilizamos el paquete $TMP que es local y por lo tanto no transportable (Es decir. abrimos un menú emergente y escogemos Create Æ Package. Obviamente. 29 . no puede salir del ambiente DEV de desarrollo).

30 . presionamos el botón Create Request. • NetWeaver nos solicita que ingresemos una Orden de Transporte para almacenar nuestro nuevo Package.• Llenamos los campos y presionamos el botón Save.

31 . presionamos el botón Continue o presionamos Enter.• Ingresamos una descripción y grabamos. • Una vez creada y asignada la Orden de Transporte.

Atributos del Package ZARTE_PROGRAMAR • Regresamos a la sesión donde teníamos la tabla y hacemos un clic en el botón del parámetro Package. 32 .

• En nuestro caso.• Podemos ingresar el nombre del Package. presionando el botón Start Search o presionando la tecla Enter. 33 . o solicitar que se muestren todos los disponibles. • Escogemos nuestro Package con un doble clic para que quede asignado a nuestra tabla. lo mejor es escribir Z* para que nos muestre solamente los paquetes creados por nosotros o por el sistema (Definidos para los usuarios).

Ahora. • Presionamos el botón Save. entonces la misma orden aparecerá por defecto. Debemos ir a la pestaña Fields (Campos). Como creamos una orden al momento de crear el Package. podemos continuar con la creación de nuestra tabla. Y nos va a aparecer la ventana solicitando una Orden de Transporte. 34 . para poder agregar los campos necesarios para nuestra tabla. Presionamos el botón Continue o la tecla Enter.

Como se darán cuenta. Esto es porque vamos a utilizar un Predefined Type (Tipo Predefinido). para el campo Id. la interfaz de la pantalla cambia un poco. se llamará Id. y será el encargado de identificar a cada uno de los registros (También es un campo llave). • Hacemos clic en el botón Predefined Type. Y como podemos ver. El segundo campo. en el gráfico no he llenado el campo Data Element (Elemento de Datos). El primer campo que vamos a utilizar es el MANDT. que identifica al ambiente en el cual estamos trabajando (Y que es un campo llave). 35 .

• El siguiente campo también necesita un tipo predefinido.• Queremos que el tipo de dato sea CHAR y tenga una longitud de 3. Este estará relacionado con una tabla que llamaremos ZENTORNOS_PROG. los 2 primeros campos serán Mandt y Id. • El siguiente campo se llamará Entorno. agregamos una pequeña descripción del campo. así que lo llamamos Nombre y lo definimos como un CHAR de longitud 15. además. antes de continuar con la tabla ZLENGUAJES_PROG. • Al igual que en la tabla ZLENGUAJES_PROG. 36 . así que abrimos otro modo para poder crearla.

se llamará Nombre. • El tercer campo.. 2. 37 . sino que contará con un Elemento de Datos y un Dominio. Llenamos los campos como se muestra en la imagen. y no tendrá asociado un Tipo Predefinido. abrimos una nueva ventana en la SE11 y nos posicionamos en Domain (Dominio).Creando un Dominio A este Dominio. Para esto. lo llamaremos ZD_ENT_NAME.

Creando un Elemento de Datos • Una vez creado el Dominio. Se dará cuenta. Lo grabamos y lo activamos utilizando el botón Activate (Activar) o presionando Crtl + F3. nos posicionamos en Data Type (Tipo de Dato). pasamos a crear nuestro Data Element (Elemento de Datos).. 3. de que al momento de presionar el botón Create. Lo llamaremos ZE_ENT_NAME. En la misma transacción. aparece una ventana preguntándonos por el Tipo de Dato que queremos crear. Llenamos los datos como se muestra en la figura. Lo dejamos como Data Element y presionamos Enter. 38 . utilizando el Dominio que creamos.

• Como estábamos ingresando Tipos Predefinidos. Y luego debemos 39 . debemos pasar a la pestaña Field Label (Etiqueta de Campo). que no es más que la descripción del Elemento de Datos. • Grabamos y ahora debemos llenar los datos de Technical Settings (Caraterísticas Técnicas) Æ Goto Æ Technical Settings o presionar Crtl + Shift + F9. Ahora. • Regresamos a la ventana donde estábamos creando la tabla ZENTORNO_PROG. E ingresar el nombre de nuestro Elemento de Datos. La llenamos como se muestra en la figura. debemos presionar el botón Data Element . Grabamos y activamos.

llenar el Enhacement Category (Categoría de Ampliación) Æ Extras Æ Enhacement Category. Para nosotros. así que 0 es la opción a tomar. El campo Size Category (Categoría de Tamaño). nuestra tabla no contendrá mucho datos. el valor por defecto siempre será APPL0. determina la cantidad de espacio que se reservará inicialmente para la tabla. Grabamos y retrocedemos para poder acceder al Enhacement Category. 40 . El campo Data Class (Clase de Datos) especifica el área física en la cual se va a crear la tabla. en nuestro caso.

Esto nos mostrará una ventana. 41 . • Nos posicionamos sobre el campo Entorno y presionamos el botón Foreign Keys (Llaves Foráneas) . En nuestro caso. que veremos a continuación. para poder ingresar nuestro Elemento de Datos para el campo Entorno. le decimos que no. Grabamos y activamos. • Regresamos a nuestra tabla ZLENGUAJES_PROG y presionamos el botón Data Element. puesto que son tablas que hemos creado como ejemplo para el libro. Esto sirve para definir si la tabla puede ser modificada con campos adicionales.

presionamos Yes (Sí) o presionamos Enter. Y presionamos Enter. escribimos el nombre de nuestra tabla ZENTORNOS_PROG.En el campo Check Table (Tabla de Verificación). 42 . El sistema nos propone crear una asignación entre las tablas.

• El ultimo campo. Recibimos este mensaje. como se muestra en la figura. 43 . se llama CONEX_SAP y determina si el lenguaje posee algún tipo de conexión con SAP. Dejamos la ventana. Para esto. porque la llave completa de la tabla ZENTORNOS_PROG no existe en la tabla ZLENGUAJES_PROG.

Ahora. pasamos a la pestaña Value Range (Rango de Valores). Y llenamos solamente dos valores. Como ven. vamos a crear nuevamente un Dominio (ZD_CONEX_SAP) y un Elemento de Datos (ZE_CONEX_SAP). 44 . es simplemente un CHAR de 1.

45 . grabamos y activamos.• Grabamos. • Llenamos la Características Técnicas. la Categoría de Ampliación. agregamos el campo CONEX_SAP con su respectivo elemento de datos. activamos y creamos nuestro Elemento de Datos. Llenamos la pestaña Field Label (Etiqueta de Campo). • De vuelta en la tabla ZLENGUAJES_PROG. grabamos y activamos.

46 . Ingresamos algunos cuantos valores. y presionamos el botón Create Entries (Crear Entradas) o presionamos F5. es hora de agregar algunos datos.Ahora que tenemos nuestras dos tablas listas. + S. Nos vamos a la transacción SE16 (Browser de Datos). Colocamos el nombre de nuestra tabla de entornos. Y grabamos con el botón Save (Guardar) o presionamos Crtl.

queremos ver todos los valores. En nuestro caso. retrocedemos presionando el botón Back (Atrás) o presionando el botón F3. podemos presionar el botón Table Contents (Contenido de Tabla) o presionar Enter. Para poder ver los registro que hemos creado.Una vez que hemos terminado de insertar registros. Presionamos el botón Execute (Ejecutar) o presionamos F8. así que dejamos esos campos en blanco. 47 . En esta ventana. podemos hacer un filtro ya sea por Id o por Entorno.

lo cual nos indica que existen valores de los cuales podemos escoger. Para esto debemos hacer clic en ese botón o presionar F4. Cuando se posicionen en el campo Entorno. se darán cuenta de algo interesante. 48 . Seguimos el mismo procedimiento. Aparece un pequeño botón al final del campo. Ahora.Tenemos 3 registros grabados en la base de datos. es el turno de la tabla ZLENGUAJES_PROG.

49 . Lo mismo sucede con el campo CONEX_SAP. si ingresamos cualquier otro valor.Esos son los registros que ingresamos en la tabla ZENTORNOS_PROG y que ahora podemos insertar en nuestra tabla ZLENGUAJES_PROG. son los únicos valores válidos. Cabe destacar que los valores que están en la tabla ZENTORNOS_PROG. es decir. el sistema nos mostrará un mensaje de error.

es un poco tedioso. debemos regresar a la transacción SE11 y modificar la tabla ZLENGUAJES_PROG.Ingresamos algunos datos y estamos listos.. que ahora vamos a crear una vista de actualización.Creando una Vista de Actualización Para crear nuestra vista de actualización. 3. vamos a Utilities (Utilidades) Æ Table Maintenance Generator (Generador de Mantenimiento de Tabla). les parecerá que ingresar los datos así. 50 .. En el menú. Seguramente.No se preocupen. Llenamos la ventana como se muestra a continuación..

En esta ventana. 51 . siempre escogemos la primera opción Propose Screen Number(s) (Proponer número(s) de Ventana). Number(s) (Buscar Número(s) de Pantalla) o presionamos Shift + F7.Presionamos el botón Find Scr.

los dos primeros campos aparecen como 52 . pero como se darán cuenta.Finalmente presionamos el botón Create (Crear) o presionamos F6. Se nos muestra una pantalla más amigable para el ingreso de datos. Grabamos y activamos. Y presionar el botón Maintain. debemos ir a la transacción SM30. Ahora.

Esto es porque al ser Tipos Predefinidos. Veamos primero en el Overview Screen. 53 . Debemos hacer clic tanto en el Overview Screen (Ventana de Vista general) como en el Single Screen (Ventana sencilla).“+”. no poseen un texto descriptivo. Esto lo podemos solucionar fácilmente regresando a la transacción SE11 y al Generador de Mantenimiento de Tabla.

pero no se preocupen. que por el momento no vamos a hacer nada con esto. Debemos hacer clic en el botón Layout (Disposición) . sobre todos las cabeceras que tienen un “+”.Seguramente esta pantalla los asusta un poco. puesto que es código generado automáticamente por el NetWeaver. La pantalla del Screen Painter es la que nos interesa. 54 .

activamos y retrocedemos dos veces hasta regresar a la ventana del Generador de Mantenimiento de Tabla. Ahora. escribimos lo siguiente Y en la segunda columna: Grabamos. 55 . Hacemos doble clic en Single Screen. nos colocamos sobre la primer columna y en la ventana que dice Text (Texto).Debemos hacer un clic en el botón Display <-> Change (Mostrar <- > Cambiar) o presionar F1.

Grabamos. regresamos a la transacción SE11 para crear una nueva y última tabla con las siguientes características.Y repetimos la operación. nos vamos a la transacción SM30 y veremos que los símbolos “+” han sido reemplazados por los textos correctos. Ahora. activamos y regresamos nuevamente. Una vez hecho esto. para hacer las cosas más interesantes y poder trabajar mejor los ejemplos del libro. modificando los símbolos “+”. 56 .

57 .La tabla se llamará ZPROGRAMAS y contendrá algunos programas que hemos hecho utilizando los lenguajes de programación que hemos creado. creamos un dominio para el código del lenguaje de programación. Ahora. creamos un Elemento de Datos llamado ZE_ID_LENGUAJE. En otra ventana. llamado ZD_ID_LENGUAJE.

Regresamos a la tabla ZPROGRAMAS y tendremos la siguiente estructura: Para que esto funcione correctamente y podamos hacer una asociación entre las tablas ZPROGRAMAS y ZLENGUAJES_PROG. debemos modificar la tabla 58 .

regresamos a ZPROGRAMAS y nos posicionamos en el campo Id y presionamos el botón Foreign Keys .ZLENGUAJES_PROG incluyendo el Elemento de Datos que creamos: Luego de haber grabado y activado. 59 .

. Como solamente hemos asignado el campo Id a nuestra tabla. al momento de querer elegir un lenguaje de programación.Creando una Ayuda de Búsqueda Para esto.Grabamos. Elegimos la primera opción. solamente vamos a ver el código. actualizamos las Características Técnicas y la Categoría de Amplicación y activamos la tabla. vamos a la transacción SE11. así que hora de crear una ayuda de búsqueda. 60 . en una nueva ventana. lo cual no nos va a ayudar de mucho. Y escogemos la opción Seach Help (Ayuda de búsqueda). 4.

el campo Nombre tiene asignamos un elemento de datos. creamos un Dominio y un Elemento de Datos como se muestra a continuación. así que nuevamente. 61 .Como pueden ver.

Grabamos y activamos nuestra ayuda de búsqueda y la probamos con presionando el botón Test (Prueba) o presionando F8. 62 .

y presionamos el botón Search Help . en este caso. 63 . Nos posicionamos en el campo Id. podemos filtrar por Id o por Nombre del lenguaje. así que regresamos a la tabla ZPROGRAMAS a la pestaña Entry Help/Check (Entrada de Ayuda/Verificación). Nuestra ayuda de búsqueda está terminada. presionamos Enter porque queremos ver todos los registros disponibles.En esta ventana.

64 . Grabamos y activamos. En la transacción SE16 agregamos algunos cuantos registros.Asignamos la ayuda de búsqueda que creamos.

.Creando una Estructura En la transacción SE11. que no es otra caso que una tabla que solamente contiene una cabecera. Con esto terminamos y podemos crear una estructura. nuestra tabla contendrá los siguientes registros. al hacer F4 en el campo Id. Finalmente.Como podemos ver. Esto nos va a ser útil al momento de desarrollar nuestros programas. es decir. 65 . puesto que vamos a poder contar con la estructura sin utilizar memoria adicional de la base de datos. creamos nuestra estructura llamada ZSLENGUAJES_PROG. no puede almacenar registros. podremos ver tanto el código como el nombre del Lenguaje. 5. en el campo Data type.

Llamada ZVLENGUAJES_PROG. creamos nuestra vista en el campo VIEW (Vista).Creando una Vista Dentro de la transacción SE11. 6. Utilizamos los mismos componentes que en la tabla ZLENGUAJES_PROG.Cuando presionamos Create (Crear) . Grabamos y activamos.. aunque quitamos el campo MANDT. el Enhacement Category (Categoría de ampliación). se nos muestra una ventana en donde debemos elegir Structure (Estructura). lo agregamos para poder activar. 66 . Nos va a pedir.

Los demás tipos no los vamos a ver en este libro. debemos de llenar los campos que vamos a utilizar para relacionar las tablas que vamos a utilizar en la vista.En la ventana que aparece. ZPROGRAMAS y ZLENGUAJES_PROG. puesto que el Database view es el más utilizado. en este caso. 67 . Primero. elegimos Database view (Vista de Base de Datos).

+ Shift + F10. Los mensajes de advertencia. podemos obviarlos. Grabamos y activamos. Se darán cuenta de que el sistema no envía a la transacción SE16. 68 . podemos comprobar los valores presionando el botón Contents (Contenidos) o presionando Ctrl. Definimos los campos que queremos que se muestren en la vista. Una vez que la Vista está activa. Ejecutamos y vemos los datos generados por la Vista.En la pestaña View Flds (Campos de la Vista).

dominios o vistas. 69 .Con esto. ya pueden crear sus propias tablas. elementos de datos. terminamos el capítulo dedicado a Diccionario de Datos. Ahora.

Cabe de destacar que muchos de los componentes de NetWeaver han sido desarrollados utilizado ABAP. PASCAL y SQL Server. En el presente capítulo. Hasta la versión 45B. viene a ser una especie de nieto del COBOL (Common Object Business Oriented Language). es el lenguaje de programación propietario de SAP AG. en versiones posteriores de NetWeaver. se adicionarán algunos componentes extras. el ABAP. así como la estructura de los programas que se crean con el. vamos a revisar los principales componentes del ABAP. 70 . aunque como es de suponerse. aunque con el tiempo se el agregaron funcionalidades para convertirlo en un lenguaje orientado a objetos. que era muy utilizado para el desarrollo de aplicaciones empresariales. lo cual significa que nos permite trabajar con ABAP Objects de manera muy completa.0. lo cual nos permite hacer modificaciones que otro tipo de sistemas serían imposibles. era un lenguaje procedural.Programación en ABAP Introducción ABAP (Advances Business Application Programming).0. podemos tomarlo como un híbrido entre COBOL. El NetWeaver actualmente está en la versión 7. se pueden mezclar ambas tecnologías sin mayores problemas. El ABAP. con el cual se desarrollan aplicaciones que son integradas al NetWeaver. por lo cual al momento de programar. En cuanto a la sintaxis de lenguajes.

Recodemos que debemos utilizar la letra Z antes del nombre del programa. en donde debemos escoger el Type (Tipo de programa) y el Status (Estado) asociado.Estructura de un programa en ABAP Para crear un programa en ABAP. el sistema nos mostrará la siguiente ventana. Esto es porque SAP. Cuando presionamos el botón Create (Crear). 71 . reserva el nombre Z para los programas que son creados por los clientes y no por los mismos trabajadores de SAP. y especificar el nombre del programa que queremos crear. debemos ingresar a la transacción SE38.

nos envía al Editor ABAP. que existen ciertos comentarios. nos va a pedir el paquete al cual queremos asignar el desarrollo. que es donde vamos a poder crear nuestros programas. elegimos ZARTE_PROGRAMAR. Debemos tener claro. para poder definir algunos bloques importantes. elegimos la creamos puesto que se nos muestra por defecto (Siempre y cuando no hayamos creado otras ordenes). elegimos SAP Standard Production Program (Programa Standard SAP para Productivo). El sistema. Al presionar el botón Save .En Type (Tipo) siempre escogemos Executable program (Programa ejecutable) y en Status (Estado). 72 . Y cuando nos pida la orden de transporte. que debemos colocar en todos nuestros programas.

debemos incluir por ejemplo. veremos la sintaxis de ABAP y podremos hacer programas más complejos. vamos a hacer un programa muy simple. quien está creando el programa y cuando. que simplemente solicite al usuario un texto y lo imprima en pantalla. La primera y única línea que nos muestra el editor es REPORT y el nombre de nuestro programa. 73 . Para empezar.En el espacio de comentario. Esto indica que se trata de un programa ejecutable. luego de esto.

es el nombre que le estamos asignando al bloque de parámetros. WITH FRAME TITLE.*&----------------------------------------------------* *& Report ZDUMMY_PRIMER_PROGRAMA * *&----------------------------------------------------* *& Creado por: Alvaro "Blag" Tejada Galindo. nos permite definir un espacio en donde van a ir los parámetros de entrada de nuestro programa. en este caso 74 . significa que el área de los parámetros de selección va a estar rodeados por un marco y TITLE. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK PRUEBA WITH FRAME TITLE TEXT-T01. PARAMETERS: TEXTO(30) TYPE C. SELECTION-SCREEN END OF BLOCK PRUEBA. significa que va a contar con un título definido por nosotros. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. El SELECTION-SCREEN BEGIN OF BLOCK. WRITE: TEXTO. * *& Fecha creación: 14 de Noviembre del 2007 * *&----------------------------------------------------* REPORT ZDUMMY_PRIMER_PROGRAMA. PRUEBA.

simplemente deberemos hacer doble clic en el texto. podemos utilizar 2 tipos de parámetros: • PARAMETERS ÆSon parámetros simples que aceptan solamente un valor. • SELECT-OPTIONS ÆSon parámetros compuestos que aceptan un rango de valores. ingresamos el texto. nos aparecerá la siguiente ventana: Simplemente. 75 . Para poder modificarlo. TEXT-T01. lo podemos separar en dos partes TEXT. que nos indica que es un texto del sistema y T01.TEXT-T01. Dentro del bloque que hemos definido para los parámetros. es el nombre de dicho texto. grabamos y activamos. Si no lo hemos creado.

TEXTO(30) TYPE C. deberemos de ingresar al siguiente menú. si queremos cambiar el texto que muestra nuestro parámetro. es un CHAR de 30 caracteres.El parámetro que hemos utilizado en este programa. veremos el parámetro de entrada que definimos. 76 . GotoÆText ElementsÆSelection Texts. Si activamos y ejecutamos el reporte (Presionando la tecla F8). Ahora.

volvamos a ejecutar el reporte. deberemos de ingresar el texto que queremos que tenga nuestro parámetro.Aquí. lo grabamos. lo activamos y listo. 77 . Ahora.

El START-OF-SELECTION. que lo único que hace es separar un espacio en memoria. WRITE: TEXTO. nos indica que va a comenzar la ejecución de nuestro programa. el valor que hemos ingresado en el parámetro de entrada TEXTO. Declaración de Variables y Tablas Internas Para poder declarar variables. es aquí donde colocamos toda la lógica. utilizamos la sentencia DATA. significa que vamos a escribir en la pantalla. DATA: TEXTO TYPE C. 78 . Ese fue nuestro primer y más simple programa en ABAP.

podemos especificar su tamaño. 79 . podemos utilizar campos de tablas para poder hacer la declaración de variables.0’ number STRING String Variable Empty string XSTRING Byte Sequence Variable Empty X String Adicionalmente.Aquí estamos diciendo que vamos a crear una variable llamada TEXTO. tenemos: C Character 1 Space N Numeric String 1 ’00…0’ D Date 8 ‘000000000’ (YYYYMMDD) T Time 6 ‘000000’ (HHMMSS) X Byte 1 X’00’ (Hexadecimal) I Integer 4 0 P Packed Integer 8 0 F Floating point 8 ‘0. DATA: TEXTO(30) TYPE C. Entre los tipos de datos que nos ofrece el ABAP. y que va a ser de tipo C (Caracter). Además.

Por lo tanto. 80 . TYPES: BEGIN OF TY_TABLA. DATA: T_TABLA TYPE STANDARD TABLE OF TY_TABLA. V_CARRID es un CHAR de 3 caracteres. … END OF TABLA. En este caso. Ahora veamos las tablas internas. esto no es posible. así que de ahora en adelante. vamos a utilizar y aprender solamente las nuevas sintaxis que se nos ofrecen gracias a la creación del ABAP Objects. son tablas temporales que existen solamente en el ámbito del programa que las creó y permiten almacenar información para luego poder manipularla sin tener que acceder múltiples veces a la base de datos. estamos declarando una variable que va a ser exactamente igual que el campo CARRID de la tabla SPFLI. … END OF TY_TABLA. Con la introducción de NetWeaver. que son uno de los elementos más valiosos del ABAP. Las tablas internas. DATA: V_CARRID TYPE SPFLI-CARRID. podíamos utilizar la siguiente sintaxis: DATA: BEGIN OF TABLA OCCURS 0. En versiones anteriores.

Primero. Esto podemos hacerlo de dos maneras. Es por eso. Para los que ya conocen ABAP. lo cual facilitaba la lectura de datos. TYPES: END OF TY_SPFLI. está prohibido utilizar cabeceras o workareas. podiamos crear tablas internas con líneas de cabecera. que SAP decició eliminar la cabeceras completamente. un tipo de tabla interna y luego. podemos también incluir estructuras completas de Base de Datos. Para los que no conocen ABAP. DATA: T_SPFLI TYPE STANDARD TABLE OF TY_SPFLI. 81 . ni tampoco WITH HEADER LINE. INCLUDE STRUCTURE SPFLI. dependiendo de si queremos o no incluir campos adicionales. de la manera que hemos visto. Además de crear tablas internas. Es decir. es decir. TYPES: TEST TYPE STRING. pero que al mismo tiempo ocasionaba problemas de performance. DATA: T_SPFLI TYPE STANDARD TABLE OF SPFLI. en versiones anteriores. debemos crear un TYPE. creamos una tabla interna que haga referencia a nuestro tipo de tabla. en ABAP Objects. no utilizamos ni OCCURS 0. Esto es porque. utilizando el DATA. TYPES: BEGIN OF TY_SPFLI. se darán cuenta de que no hemos creado la tabla con una cabecera.

NOMBRE(30) TYPE C. DATA: TEST_H TYPE HASHED TABLE OF TY_TEST WITH UNIQUE KEY ID. EDAD TYPE I. tenemos 3 tablas internas. NOMBRE TYPE STRING. TYPES: BEGIN OF TY_TEST. END OF TY_TEST. 82 . lo hacemos de la siguiente forma. DATA: TEST TYPE STANDARD TABLE OF TY_TEST.Claro. TYPES: BEGIN OF TY_TEST. END OF TY_TEST. ID(3) TYPE C. DATA: TEST TYPE STANDARD TABLE OF TY_TEST. si queremos crear una tabla interna que tenga datos propios. Seguramente se habrán dado cuenta y sobre todo se preguntarán. muy simple. EDAD TYPE I. porque tenemos que utilizar el TYPE STANDARD TABLE. porque tenemos disponibles más tipos de tablas. DATA: TEST_S TYPE SORTED TABLE OF TY_TEST WITH UNIQUE KEY ID Como pueden ver.

para poder seleccionar datos. De rápido acceso. De rápido acceso. 83 . pero no puede ser accedida mediante un índice. TEST_S Æ Sorted table. SELECT SINGLE NOM_PROG INTO NOMBRE FROM ZPROGRAMAS WHERE ID_PROG EQ '001'. TEST_H Æ Tabla de tipo hashed. en lo personal. En realidad. ya sea en Variable o en Tablas internas. siempre está ordenada. solo he utilizado este tipo de tablas algunas cuantas veces en toda mi carrera. Aunque en el caso de ABAP. depende del nivel de nivel de datos o de la complejidad del programa. Selección de Datos Al igual que en SQL. Puede ser accedida mediante un índice o mediante campos. el uso de tablas Hashed o Sorted. no puede ser accedida mediante un índice. podemos utilizar la clásica sentencia SELECT. tenemos mayor flexibilidad para poder almacenar los datos.TEST Æ Tablas Standard. En Variables: DATA: NOMBRE TYPE ZPROGRAMAS-NOM_PROG.

TYPES: BEGIN OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. también podemos utilizar INNER JOINS para hacer nuestras consultas. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. END OF TY_PROGRAMAS.Declaramos una variable llamada NOMBRE del tipo del campo NOM_PROG de la tabla ZPROGRAMAS. Hacemos un SELECT SINGLE para obtener un registro cuyo campo ID_PROG sea igual a 001. Claro. END OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. SELECT NOM_PROG INTO TABLE T_PROGRAMAS FROM ZPROGRAMAS. 84 . En Tablas internas: TYPES: BEGIN OF TY_PROGRAMAS. En esta caso. creamos un TYPE. luego una tabla interna y finalmente leemos todas las instancias del campo NOM_PROG dentro de nuestra tabla interna.

aunque claro. supongamos que tenemos un campo más en nuestra tabla interna. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. pero no queremos seleccionarlo. el SELECT va a estar incompleto y los registros pueden guardarse donde no les corresponde. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. así que lo mejor es evitarlos. END OF TY_PROGRAMAS.DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. 85 . NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. Esto lo podemos solucionar utilizando un INTO CORRESPONDING FIELDS. esto afecta el performance de nuestros programas. Ahora. SELECT NOMBRE ENTORNO NOM_PROG INTO CORRESPONDING FIELDS OF TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). TYPES: BEGIN OF TY_PROGRAMAS. entonces. que lo que hace es almacenar los registros en los campos correspondientes. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP.

debemos de leerlas para poder hacer algo con ellas. creamos una referencia a la tabla T_TABLA. los Fields-Symbols. debemos conocer un elemento muy importante. Estamos hablando de los Field-Symbols. Con esto. antes de eso. con lo cual ganamos mucho performance al hacer lecturas de tablas internas. la cual contiene únicamente una línea de cabecera.Lectura de datos de Tablas Internas Una vez que tenemos datos en nuestras tablas internas. Para los que han programado alguna vez en C++. contamos con dos opciones. FIELD-SYMBOLS: <FS_TABLA> LIKE LINE OF T_TABLA. Aunque. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. END OF TY_PROGRAMAS. es decir. almacenas la dirección en memoria de una variable. 86 . Para eso. son muy parecidos a los punteros. sin el cual no podríamos hacer mucho en ABAP. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. Por lo general. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. • LOOP AT TYPES: BEGIN OF TY_PROGRAMAS. los utilizamos para crear cabeceras de tablas internas.

WRITE:/ <FS_PROGRAMAS>-NOM_PROG. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). utilizando un WRITE imprimimos el contenido del campo NOM_PROG. y al asignar cada uno de estos registros a nuestro Field-Symbol. Al hacer un LOOP AT. lo que estamos haciendo es pasar simplemente la cabecera de ese registro. El símbolo / nos sirve para dejar un espacio hacia abajo luego de haber impreso el valor (Equivales a hacer un ENTER). LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. por lo cual la lectura de la tablas es mucho más veloz. lo que hacemos es leer cada uno de los registros almacenados en nuestra tabla interna. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. Finalmente.DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ENDLOOP. 87 .

READ TABLE T_PROGRAMAS WITH KEY NOMBRE = 'PHP' ASSIGNING <FS_PROGRAMAS>. En este caso. END OF TY_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. podemos utilizar 88 . DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.• READ TABLE TYPES: BEGIN OF TY_PROGRAMAS. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). al utilizar un READ TABLE. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. como podemos ver. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. leemos un solo registro de nuestra tabla.

89 . =. Operadores de Comparación Un proceso muy común. un Indice o también un Campo para leer el contenido y asignarlo a nuestro Field-Symbol. LE Menor igual Ambos tipos de comandos son equivalentes. EQ Igual a <>. ENDIF. LT Menor que >=. GT Mayor que <. para esto. WRITE:/ ‘Viva PHP!’. GE Mayor igual <=. es el comparar valores entre variables o tablas internas. NE Distinto a >. WRITE:/ ‘Viva PHP!’. contamos con los siguientes comandos. por lo tanto es lo mismo decir: IF NOMBRE EQ ‘PHP’. Que decir: IF NOMBRE == ‘PHP’.

vamos a crear una pequeña aplicación. ENDIF. *=====================================================* * FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE 90 . ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. Para poder afianzar los conocimientos adquiridos hasta el momento. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. *=====================================================* * DECLARACION DE TABLES * *=====================================================* TABLES: ZPROGRAMAS.

WRITE:/1 'Lenguaje'. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01.33 'Programa'. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ) WHERE ZPROGRAMAS~ID IN S_ID. WRITE:/ SY-ULINE(45). WRITE:/ <FS_PROGRAMAS>-NOMBRE. SELECTION-SCREEN END OF BLOCK PRG.OF T_PROGRAMAS. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>.<FS_PROGRAMAS>-ENTORNO. ENDLOOP. 91 .17 'Entorno'. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. <FS_PROGRAMAS>-NOM_PROG. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.

TYPES: BEGIN OF TY_PROGRAMAS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ZDUMMY_PRIMER_PROGRAMA es el nombre de nuestro programa. 92 . DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. END OF TY_PROGRAMAS. TABLES indica que vamos a utilizar una tabla para hacer referencia a un campo en el SELECTION-SCREEN. REPORT indica que estamos creando y ejecutando un programa.Analicemos un poco el programa antes de ejecutarlo y ver el resultado. NO STANDARD PAGE HEADING. TABLES: ZPROGRAMAS. TYPES indica que vamos a crear un tipo de tabla definido por nosotros. indica que no queremos que el título del programa se muestre en el output del reporte. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO.

SELECTION-SCREEN END OF BLOCK PRG. SELECTION-SCREEN BEGIN OF BLOCK indica el inicio de un bloque de parámetros.DATA indica que vamos a crear una variable o una tabla interna. TYPE STANDARD TABLE indica que la tabla es de tipo STANDARD. <FS_PROGRAMAS> es el nombre de nuestro field-symbol. TY_PROGRAMAS es el nombre del tipo de tabla que creamos y al cual va a hacer referencia nuestra tabla interna. LIKE LINE OF indica que va a representar una línea de cabecera de una tabla interna. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. PRG es el nombre del bloque de parámetros. T_PROGRAMAS es el nombre de nuestra tabla interna. SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. FIELD-SYMBOLS crea un field-symbol. OF indica a que tipo de dato va a hacer referencia nuestra tabla interna. 93 . T_PROGRAMAS es la tabla interna de la cual el field-symbol va a representar la cabecera. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID.

START-OF-SELECTION. S_ID es el nombre del SELECT-OPTION. NOMBRE ENTORNO NOM_PROG son los campos que queremos seleccionar. 94 . SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ) WHERE ZPROGRAMAS~ID IN S_ID. FOR indica que hace referencia a un campo de Base de Datos. ZPROGRAMAS-ID es el nombre de la Base de Datos y el campo respectivamente. SELECTION-SCREEN END OF indica el fin del bloque de parámetros. T01 contiene el título. TITLE TEXT indica que el bloque de parámetros debe tener un título. START-OF-SELECTION indica el inicio de nuestro programa.WITH FRAME indica que nuestro bloque de parámetro debe tener un marco (más que nada un tema de visualización). SELECT-OPTIONS indica que es un parámetros con rango de valores. SELECT indica que queremos seleccionar datos.

‘Entorno’ y ‘Programa’ son los texto que queremos escribir. FROM indica de donde queremos obtener los datos. 95 . WHERE indica el parámetro de restricción del SELECT.17 'Entorno'. 1. 17 y 33.INTO TABLE indica en que tabla interna queremos guardar los datos. WRITE:/1 'Lenguaje'. IN indica que el campo del filtro debe de estar dentro de los valores del SELECT-OPTION. WRITE:/ SY-ULINE(45). indican las posiciones X en las cuales queremos escribir. T_PROGRAMAS es la tabla donde vamos a guardar los datos. / indica que luego de escribir en la pantalla queremos hacer un salto de líneas. WRITE indica que queremos escribir algo en la pantalla. ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS indica que queremos realizar un INNER JOIN entre estas dos tablas ON indica el parámetro de igualdad de campos del INNER JOIN. S_ID es el SELECT-OPTION contra el cual vamos a validar el campo ZPROGRAMAS~ID. ZPROGRAMAS~ID es el campo por el cual queremos hacer el filtro. ‘Lenguaje’. ZLENGUAJES~ID = ZPROGRAMAS~ID indica que el campo ID de ambas tablas va a utilizarse como campo de igualdad.33 'Programa'.

LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. 96 . T_PROGRAMAS es la tabla interna de la cual vamos a leer los registros. WRITE:/ <FS_PROGRAMAS>-NOMBRE. <FS_PROGRAMA>-NOMBRE es el nombre del campo que queremos escribir en la pantalla. ENDLOOP.<FS_PROGRAMAS>-ENTORNO.SY-ULINE(45) es una variable del sistema que nos permite dibujar una línea. <FS_PROGRAMAS>-NOM_PROG. El 45 entre paréntesis indica la longitud de la línea. <FS_PROGRAMAS> es el nombre del Field-Symbol. LOOP AT indica que vamos a recorrer todos los registros de una tabla interna. Ahora que ya hemos revisado todo el programa línea por línea. ENDLOOP indica el fín del LOOP. podemos ejecutarlo. ASSIGNING <FS_PROGRAMAS> indica que vamos a asignar el registro leído a un Field-Symbol.

33 'Programa'. 97 . FORMAT COLOR OFF.Si queremos que nuestro programa se vea un poco más colorido. FORMAT COLOR 5. WRITE:/1 'Lenguaje'.17 'Entorno'. podemos agregar un par de líneas. WRITE:/ SY-ULINE(45).

98 .FORMAT COLOR indica que queremos pintar el fondo de un color. 5 representa al color verde. FORMAT COLOR OFF indica que ya no queremos seguir pintando el fondo de un color. modificar o eliminar registros (Ya sea porque no nos sirven o porque están duplicados). ID_PROG TYPE ZPROGRAMAS-ID_PROG. Veamos como manejar esto: • Agregando registros TYPES: BEGIN OF TY_PROGRAMAS. muchas veces se necesita agregar. El reporte quedaría así: Operaciones en tablas internas Cuando se trabaja con tablas internas.

READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. WRITE:/ <FS_PROGRAMAS>-ID_PROG. Pero como esta no tiene cabecera. agregamos los valores a la tabla y al momento de leerla con el índice 1. Como vemos. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. entonces debemos asignarle una utilizando APPEND INITIAL LINE TO y asignándola a <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. END OF TY_PROGRAMAS. podemos imprimir los nuevos valores. 99 . creamos una tabla interna. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. Luego. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.

WRITE:/ <FS_PROGRAMAS>-ID_PROG. WRITE:/ 'Modificamos el registro'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. SKIP 1. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. ID_PROG TYPE ZPROGRAMAS-ID_PROG. <FS_PROGRAMAS>-ID_PROG = '006'. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. END OF TY_PROGRAMAS. 100 . WRITE:/ <FS_PROGRAMAS>-NOM_PROG.• Modificando registros TYPES: BEGIN OF TY_PROGRAMAS. SKIP 1.

APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. leemos el primer registro y lo asignamos a <FS_PROGRAMAS>. En esta caso solamente 1. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. WRITE:/ <FS_PROGRAMAS>-ID_PROG. Tomando el ejemplo anterior. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. esta sentencia nos permite realizar saltos de línea. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. 101 . Podrán ver que además. • Eliminado registros TYPES: BEGIN OF TY_PROGRAMAS. Simplemente escribimos el nuevo valor para que se modifique automáticamente. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. estamos utilizando la sentencia SKIP. END OF TY_PROGRAMAS. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG.

<FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. TYPES: BEGIN OF TY_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. Ahora. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. eliminaríamos todos los registros). DELETE T_PROGRAMAS WHERE ID_PROG EQ '006'. supongamos que tenemos registros repetidos y queremos eliminarlos sin preocuparnos por el índice (Puesto que eliminado por campo. y como podemos ver.<FS_PROGRAMAS>-ID_PROG = '006'. Asignamos dos registros a nuestra tabla interna. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. END OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '007'. podemos eliminarlos utilizando ya sea un índice o uno de los campos como parámetro de búsqueda. ID_PROG TYPE ZPROGRAMAS-ID_PROG. 102 . DELETE T_PROGRAMAS INDEX 1.

DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS. TYPES: BEGIN OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'. Como podemos ver. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. más no el campo NOM_PROG. tenemos dos veces el mismo registro. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. ID_PROG TYPE ZPROGRAMAS-ID_PROG. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. END OF TY_PROGRAMAS. Claro. <FS_PROGRAMAS>-ID_PROG = '006'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. 103 . por lo tanto utilizamos DELETE ADJACENT DUPLICATES para dejar solamente uno de los dos registros.FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. Entonces debemos hacer algo más. quizás se podría dar el caso de que solamente el campo ID_PROG esté repetido.

FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. En este caso. Copiar tablas internas Algunas veces. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. <FS_PROGRAMAS>-ID_PROG = '006'. con lo cual solamente se toma en cuenta el campo ID_PROG para hacer la validación de registros repetidos. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. las tablas tienen la misma estructura o tienen una estructura distinta. 104 . Simplemente debemos agregar un COMPARING. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. dos opciones. necesitamos copiar el contenido de una tabla interna a otra. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS COMPARING ID_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'.

poseen exactamente la misma estructura. En este caso. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'. podemos utilizar el [] para copiar los datos de una tabla a otra.• Copiar tablas con la misma estructura TYPES: BEGIN OF TY_PROGRAMAS. ambas haciendo referencia a TY_PROGRAMAS. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. 105 . ID_PROG TYPE ZPROGRAMAS-ID_PROG. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. T_PROGRAMAS_AUX[] = T_PROGRAMAS[]. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. END OF TY_PROGRAMAS. Por ello. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS. tenemos las dos tablas internas T_PROGRAMAS y T_PROGRAMAS_AUX. por lo tanto.

<FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS_AUX.• Copiar tablas con diferente estructura TYPES: BEGIN OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. APPEND INITIAL LINE TO T_PROGRAMAS_AUX 106 . ID_PROG TYPE ZPROGRAMAS-ID_PROG. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. TYPES: BEGIN OF TY_PROGRAMAS_AUX. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ID TYPE ZPROGRAMAS-ID. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. END OF TY_PROGRAMAS_AUX. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. END OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'.

END OF TY_PROGRAMAS_AUX. Creamos un tipo de tabla llamado TY_PROGRAMAS_AUX al cual le agregamos el campo ID. En vez de eso. ID_PROG TYPE ZPROGRAMAS-ID_PROG. ASSIGNING <FS_PROGRAMAS_AUX>. MOVE <FS_PROGRAMAS>-NOM_PROG TO <FS_PROGRAMAS_AUX>-NOM_PROG. ID_PROG TYPE ZPROGRAMAS-ID_PROG. TYPES: BEGIN OF TY_PROGRAMAS. pero si tenemos por decir 20 campos. TYPES: BEGIN OF TY_PROGRAMAS_AUX.Entonces debemos utilizar una forma alternativa.. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.. por lo cual no podemos seguir utilizando el []. con lo cual hacemos que ambas tablas internas sean distintas. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. END OF TY_PROGRAMAS. Eso está bien para algunos campos. T_PROGRAMAS_AUX TYPE STANDARD TABLE 107 . DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. MOVE <FS_PROGRAMAS>-ID_PROG TO <FS_PROGRAMAS_AUX>-ID_PROG. ID TYPE ZPROGRAMAS-ID. ENDLOOP. debemos hacer un LOOP y asignar los valores de la tabla T_PROGRAMAS a la tabla T_PROGRAMAS_AUX.

108 . APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. ya se solamente tenemos una forma de hacerlo. MOVE-CORRESPONDING <FS_PROGRAMAS> TO <FS_PROGRAMAS_AUX>. Cuando utilizamos el MOVE-CORRESPONDING. OF TY_PROGRAMAS_AUX. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'. APPEND INITIAL LINE TO T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. lo que hacemos es que el ABAP se encargue de mover todos los campos de la tabla T_PROGRAMAS a la tabla T_PROGRAMAS_AUX. ENDLOOP. Ordenar tablas internas Esto es bastante simple.

FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. SORT T_PROGRAMAS BY ID_PROG DESCENDING.TYPES: BEGIN OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'. Utilizamos la sentencia SORT para ordenar una tabla interna. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. podemos incluir BY para indicar por cual o cuales campos debería ordenarse y además podemos indicar si la ordenación es Ascending (Ascendente) o Descending (Descendente). <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '005'. SORT T_PROGRAMAS BY ID_PROG ASCENDING. END OF TY_PROGRAMAS. 109 . ID_PROG TYPE ZPROGRAMAS-ID_PROG. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.

Estructuras de Control Como vimos. ¿Pero que pasa si lo que necesitamos es recorrer los posibles valores de una variable? Para estos casos contamos con WHILE-ENDWHILE. ENDDO. WHILE VAR LT 10. Aumentamos el valor de VAR de uno en uno. ENDWHILE. Esto significa que mientras la variable VAR sea menor o igual a 10. WRITE:/ VAR. ENDIF. DATA: VAR TYPE I. 110 . podemos utilizar un LOOP para recorrer todos los registros de una tabla interna. DATA: VAR TYPE I. ELSE. VAR = VAR + 1. DO. EXIT. También tenemos presente el DO-ENDO. por cada vuelta del WHILE. WRITE:/ VAR. VAR = VAR + 1. IF VAR LT 10. imprimimos el valor.

o por lo menos no tanto como otros lenguajes (Como por 111 . Adicionalmente tenemos los comandos CONTINUE y EXIT. le decimos al DO-ENDO que solo realice el bucle 10 veces. Aunque. En el caso afirmativo imprimimos y aumentamos en uno. En esta caso. Cuando VAR es mayor a 10.El DO-ENDDO es un bucle repetitivo que avanza mientras no le digamos que tiene que salir. ENDDO. Utilizando un IF preguntamos si el valor de la variable es menor o igual a 10. salimos del DO-ENDDO utilizando un EXIT. que sirven para continuar en la siguiente iteración de la estructura de la estructura de control o para salir de la estructura de control completamente. también podríamos haberlo escrito así: DATA: VAR TYPE I. WRITE:/ VAR. Trabajando con Cadenas de Texto Si bien el ABAP no está diseñado para trabajar con cadenas de texto. DO 10 TIMES. Imprimimos el valor de la variable VAR y la aumentamos en uno. VAR = VAR + 1.

DATA: VAR TYPE STRING. Con TO UPPER CASE convertimos a Mayúsculas y con TO LOWER CASE convertimos a Minúsculas. VAR_TEXT TYPE STRING. • CONCATENATE Concatena dos o más cadenas de texto. WRITE:/ VAR.ejemplo PERL). une cadenas en una cadena más grande. WRITE:/ VAR. VAR = 'El Arte de Programar'. TRANSLATE VAR TO UPPER CASE. 112 . DATA: VAR TYPE STRING. TRANSLATE VAR TO LOWER CASE. VAR_AUX TYPE STRING. de todos modos nos brinda alguna poderosas herramientas como estas: • TRANSLATE Convierte una cadena de texto a Mayúsculas o Minúsculas. Es decir.

CONCATENATE VAR VAR_AUX INTO VAR_TEXT. VAR = 'El Arte de Programar'. DATA: VAR TYPE STRING. WRITE:/ VAR_TEXT. Con el CONCATENATE decimos que los valores de las variables VAR y VAR_AUX se guarden en la variable VAR_TEXT. en este caso al utilizar SPACE le 113 . si ejecutamos el programa nos daremos cuenta de que no hay ningún espacio entre las dos palabras. Aunque claro. esto lo arreglamos fácilmente. VAR_AUX = 'SAP NETWEAVER'.VAR = 'El Arte de Programar'. VAR_AUX TYPE STRING. VAR_TEXT TYPE STRING. Simplemente agregamos un SEPARATED BY al final del CONCATENATE. VAR_AUX = 'SAP NETWEAVER'. CONCATENATE VAR VAR_AUX INTO VAR_TEXT SEPARATED BY SPACE. WRITE:/ VAR_TEXT.

VAR_TEXT TYPE STRING. WRITE:/ VAR. WRITE:/ VAR_TEXT. SPLIT VAR_TEXT AT SPACE INTO VAR VAR_TEXT. END OF TY_CADENAS. VAR_AUX TYPE STRING. TYPES: BEGIN OF TY_CADENAS. DATA: T_CADENAS TYPE STANDARD TABLE OF TY_CADENAS. Utilizamos el SPLIT para dividir la cadena utilizando como aguja un espacio y pasamos los valores a las variables VAR y VAR_TEXT. • SPLIT Divide una cadena en subcadenas. DATA: VAR TYPE STRING. 114 . VAR_TEXT = 'SAP NETWEAVER'. VAR(30) TYPE C. estamos diciendo que separe el texto con un espacio en blanco. dependiendo de un carácter aguja.

DATA: VAR_TEXT TYPE STRING. Utilizando el SHIFT LEFT DELETING LEADING eliminamos los espacios en blanco del inicio de la cadena. VAR_TEXT = 'SAP NETWEAVER'. SHIFT VAR_TEXT RIGHT DELETING TRAILING SPACE. 115 . DATA: VAR_TEXT TYPE STRING. Creamos un tipo de tabla con un campo llamado VAR de tipo C y longitud 30. • SHIFT Utilizado con la sentencia DELETING. Declaramos una variable de tipo STRING y utilizando el SPLIT mandamos las subcadenas a la tabla interna. permite eliminar los espacios o caracteres al inicio o al final de una cadena de texto. La variable VAR_TEXT tiene cinco espacios al inicio y cinco espacios al final del texto. SPLIT VAR_TEXT AT SPACE INTO TABLE T_CADENAS. SHIFT VAR_TEXT LEFT DELETING LEADING SPACE. VAR_TEXT = ' SAP NETWEAVER '. Creamos una tabla interna con referencia a nuestro tipo de tabla.

• CONDENSE Elimina los espacios en blanco. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'. Utilizando el SHIFT RIGHT DELETING TRAILING eliminamos los espacios en blanco del final de la cadena. Con el CONDENSE eliminamos todos los espacios de la cadena. CONDENSE VAR_TEXT. 116 . CONDENSE VAR_TEXT NO-GAPS. como lo hace el SHIFT. Con el CONDESE eliminamos los espacios del inicio y del final de la cadena. REPLACE SPACE WITH '/' INTO VAR_TEXT. DATA: VAR_TEXT TYPE STRING. DATA: VAR_TEXT TYPE STRING. VAR_TEXT = ' SAP NETWEAVER '. pero toma los espacios del final y del inicio al mismo tiempo. • REPLACE Reemplaza una cadena por otra.

117 . queremos que busque todas las ocurrencia de “/” y la reemplace con un espacio. Porque? Realmente no lo sé.. nuestro programa había fallado miserablemente. DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. • FIND Busca una subcadena en una cadena.. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'. En el segundo caso. REPLACE ALL OCCURRENCES OF '/' IN VAR_TEXT WITH SPACE . Con REPLACE decimos que reemplace el espacio en blanco con el caracter “/”. Si hubiéramos dicho que busque las ocurrencia del espacio y las reemplace por un “/”. DATA: VAR_TEXT TYPE STRING. FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. pero lamentablemente no pudimos hallar una respuesta adecuada.Tuvimos una emocionante discusión en el SDN (SAP Developer Network) acerca de esto. Aunque solamente va a buscar y reemplazar la primera ocurrencia del espacio. VAR_TEXT = 'SAP/NETWEAVER/PROGRAMMING'.

VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. 118 . deberíamos hacer lo siguiente: DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. WRITE:/ <FS_RESULT>-OFFSET. Si quisiéramos encontrar todas la ocurrencias de la cadena. FIND ALL OCCURRENCES OF 'SAP' IN VAR_TEXT RESULTS RESULT_TAB. READ TABLE RESULT_TAB INDEX 1 ASSIGNING <FS_RESULT>.FIND 'NETWEAVER' IN VAR_TEXT RESULTS RESULT_TAB. ENDIF. debemos asignar el resultado a la tabla interna RESULT_TAB y de ella leer la posición de la subcadena dentro de la cadena. IF SY-SUBRC EQ 0. Creamos una tabla interna llamada RESULT_TAB de tipo MATCH_RESULT_TAB (Que es un tipo predefinido en ABAP). IF SY-SUBRC EQ 0. Cuando utilizamos el FIND para hacer la búsqueda de la subcadena. FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. DATA: VAR_TEXT TYPE STRING.

Incluyendo el ALL OCCURRENCES OF podemos conocer todas las ocurrencias de una subcadena dentro de una cadena. • STRLEN Obtiene la longitud de una cadena. Variables del Sistema ABAP cuenta con variables internas del sistema que nos ayudan a conocer información importante acerca de nuestro programa o del 119 . ENDIF. ENDLOOP. LOOP AT RESULT_TAB ASSIGNING <FS_RESULT>. VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. LONG TYPE I. LONG = STRLEN( VAR_TEXT ). WRITE:/ <FS_RESULT>-OFFSET. DATA: VAR_TEXT TYPE STRING. Utilizando STRLEN podemos conocer la longitud en caracteres de una cadena de texto.

nos indica el número de “vuelta” o iteración o el índice del registro que estamos leyendo. • SY-BACTH Nos indica si el programa se está ejecutando en fondo o en modo directo. (Todas pueden ser encontradas en la tabla SYST).sistema. • SY-SUBRC Retorna un valor que determina el estado de las operaciones en ABAP. • SY-MANDT 120 . SY-SUBRC = 0 Æ Ejecutado con éxito. determina el número de página en la cual nos encontramos. • SY-LANGU Idioma de trabajo actual. • SY-PAGNO En un reporte de tipo listado. • SY-TABIX Dentro de un LOOP. Veamos cuales son las más importantes. No ha podido ejecutarse. SY-SUBRC = 4 Æ Error.

• SY-DATUM Fecha actual del sistema. • SY-REPID Nombre del programa que estamos creando o ejecutando. • SY-UZEIT Hora actual del sistema. 121 . debemos utilizar funciones para poder modularizarlos. • SY-UCOMM Nombre del código de función lanzado por un Dynpro o por un menú. • SY-TCODE El nombre de la transacción con la cual estamos trabajando. Modularización de Programas Para que nuestros programas sean más fáciles de mantener y de programas. • SY-UNAME Nombre del usuario logeado en el sistema. Nos indica el número de mandante en el cual estamos trabajando.

vamos a hacer un ejemplo. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. 122 . Y se llaman así: PERFORM XXX USING YYY CHANGING YYY TABLE YYY. *=====================================================* * DECLARACION DE TABLES * *=====================================================* TABLES: ZPROGRAMAS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING.Las funciones tienen el siguiente formato: FORM XXX USING YYY CHANGING YYY TABLES YYY. … ENDFORM. Para entender mejor a que nos referimos.

NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. SELECTION-SCREEN END OF BLOCK PRG. PERFORM OBTENER_DATOS. *=====================================================* * FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. END OF TY_PROGRAMAS. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. 123 . SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. PERFORM MOSTRAR_REPORTE. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO.

SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ) WHERE ZPROGRAMAS~ID IN S_ID.17 'Entorno'.33 'Programa'. ENDFORM.*&----------------------------------------------------* *& Form obtener_datos * *&----------------------------------------------------* FORM OBTENER_DATOS. "obtener_datos *&----------------------------------------------------* *& Form MOSTRAR_REPORTE * *&----------------------------------------------------* FORM MOSTRAR_REPORTE. <FS_PROGRAMAS>-ENTORNO. ENDLOOP. ENDFORM. WRITE:/ SY-ULINE(45). "MOSTRAR_REPORTE Se darán cuenta de que este es el mismo ejemplo que ya habíamos desarrollado. aunque ahora. lo hemos modularizado. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOMBRE. <FS_PROGRAMAS>-NOM_PROG. 124 . WRITE:/1 'Lenguaje'.

FORM OBTENER_DATOS. ENDFORM. Ahora. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: VAR TYPE STRING. PERFORM MOSTRAR_REPORTE. las funciones o FORM no hacen más que encapsular las funcionalidades que habíamos desarrollado anteriormente. llamamos a nuestras dos funciones OBTENER_DATOS y MOSTRAR_REPORTE. PERFORM OBTENER_DATOS. veamos un ejemplo que utilice las características de los FORMS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. Luego del START-OF-SELECTION.START-OF-SELECTION. "obtener_datos En este caso. Aunque de todos modos. *=====================================================* * START-OF-SELECTION * 125 . SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ) WHERE ZPROGRAMAS~ID IN S_ID. nos ayuda a tener un código más ordenado.

ENDCASE. TRANSLATE P_VAR TO UPPER CASE. "CONVERTIR 126 . PERFORM CONVERTIR USING 'L' CHANGING VAR. TRANSLATE P_VAR TO LOWER CASE. PERFORM INICIALIZAR. WRITE:/ VAR.*=====================================================* START-OF-SELECTION. ENDFORM. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. WHEN 'L'. WRITE:/ VAR. PERFORM CONVERTIR USING 'U' CHANGING VAR. "INICIALIZAR *&----------------------------------------------------* *& Form CONVERTIR * *&----------------------------------------------------* FORM CONVERTIR USING P_TIPO CHANGING P_VAR. CASE P_TIPO. ENDFORM. VAR = 'El Arte de Programar NETWEAVER'. WHEN 'U'.

En este caso. hacemos un TRANSLATE TO LOWER CASE y cambiamos el valor de P_VAR. Luego de llamar a cada PERFORM. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. utilizamos un CASE-ENDCASE para poder determinar el valor del parámetro P_TIPO. En el caso de ser U (Upper). *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. si es L (Lower). END OF TY_PROGRAMAS. En caso contrario. uno llamado INICIALIZAR donde simplemente asignamos un valor a la variable VAR y otro llamado CONVERTIR el cual recibe un valor de texto (Ya sea U o L) y cambia el valor de la variable VAR. entonces hacemos un TRANSLATE TO UPPER CASE y cambiamos el valor de P_VAR. ID_PROG TYPE ZPROGRAMAS-ID_PROG. imprimimos el valor de P_VAR. *=====================================================* 127 . Dentro del FORM CONVERTIR. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. tenemos dos FORMS.

* DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. PERFORM INICIALIZAR. " inicializar *&----------------------------------------------------* *& Form IMPRIMIR_REPORTE * *&----------------------------------------------------* FORM IMPRIMIR_REPORTE TABLES T_TABLA. LOOP AT T_TABLA 128 . <FS_PROGRAMAS>-ID_PROG = '002'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-NOM_PROG = 'TETRIS'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '001'. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. <FS_PROGRAMAS>-NOM_PROG = 'POKEMON'. ENDFORM. PERFORM IMPRIMIR_REPORTE TABLES T_PROGRAMAS. *&----------------------------------------------------* *& Form inicializar * *&----------------------------------------------------* FORM INICIALIZAR.

ASSIGNING <FS_PROGRAMAS>.
WRITE:/ <FS_PROGRAMAS>-ID_PROG.
WRITE: <FS_PROGRAMAS>-NOM_PROG.
ENDLOOP.
ENDFORM. "IMPRIMIR_REPORTE

En esta caso, nuestro FORM recibe un parámetros TABLES, es
decir una tabla interna. Por lo tanto, podemos hacerle un LOOP,
asignarla a un Field-Symbol e imprimir sus valores.

Depuración de Programas

El termino “bug” en programación, se refiere a un error o a un
evento no planeado dentro de la ejecución de un programa.
Utilizando las herramientas que nos brinda NetWeaver podemos
hacer un DEBUG (Eliminar bichos) a cualquier programa para
analizar su funcionamiento interno.
Tenemos 3 formas de iniciar un DEBUG, utilizando la palabra
reservada BREAK-POINT en nuestro código fuente, utilizar un
BREAK-POINT lógico o simplemente escribir /H en la barra de
menú. Veamos más a fondo las 3 formas.
Pero antes de comenzar, es mejor que hagamos un pequeño ajuste en
las propiedades del NetWeaver, puesto que el nuevo Debugger
(Que no vamos a revisar en este libro), es bastante complejo y
consume muchos recursos del sistema. Para esto, seguimos la ruta
Utilities Æ Settings Æ ABAP Editor Æ Debugging Æ Classic
Debugger. El Debugger clásico basta y sobra para que podamos
revisar y corregir nuestros programas.

129

Como mencioné arriba, la primera forma de activar el Debugger es
utilizar la palabra clave BREAK-POINT.

REPORT ZDUMMY_PRIMER_PROGRAMA
NO STANDARD PAGE HEADING.

*=====================================================*
* DECLARACION DE TYPES *
*=====================================================*
TYPES: BEGIN OF TY_PROGRAMAS,
ID_PROG TYPE ZPROGRAMAS-ID_PROG,
NOM_PROG TYPE ZPROGRAMAS-NOM_PROG,

130

END OF TY_PROGRAMAS.

*=====================================================*
* DECLARACION DE TABLAS INTERNAS *
*=====================================================*
DATA: T_PROGRAMAS TYPE STANDARD TABLE
OF TY_PROGRAMAS.

*=====================================================*
* DECLARACION DE FIELD-SYMBOLS *
*=====================================================*
FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE
OF T_PROGRAMAS.

*=====================================================*
* START-OF-SELECTION *
*=====================================================*
START-OF-SELECTION.
SELECT ID_PROG NOM_PROG
INTO TABLE T_PROGRAMAS
FROM ZPROGRAMAS.

BREAK-POINT.

LOOP AT T_PROGRAMAS
ASSIGNING <FS_PROGRAMAS>.
WRITE:/ <FS_PROGRAMAS>-ID_PROG,
<FS_PROGRAMAS>-NOM_PROG.
ENDLOOP.

Luego de hacer el SELECT, colocamos un BREAK-POINT, con lo
cual hacemos que el programa se detenga.

131

Cuando ejecutamos el programa, entraremos al Debugger.

Tenemos disponible el código fuente para poder ejecutarlo línea por
línea, por bloques o continuar con la ejecución.

132

Pero lo más importante es la parte del final, donde dice Field names
(Nombre de campos), puesto que ahí podemos colocar una variable
o una tabla interna para ver su contenido. Solo necesitamos escribir
su nombre o hacer doble clic sobre su nombre en la pantalla de
código.

Una vez que tenemos el nombre escrito, basta con que hagamos
doble clic para poder ver su contenido.

Además, por si esto fuera poco, contamos con botones para
manipular el contenido de los registros.

Con Change (Cambiamos el valor del registro).
Con Insert (Agregamos una nueva línea).

133

Con Append (Copiamos un registro).
Con Delete (Eliminamos un registro).
En el caso de las variables, podemos tomar como ejemplo
<FS_PROGRAMA>-ID_PROG.

Para cambiar el valor debemos sobrescribirlo y presionar el botón

Change Field Content (Cambiar contenido de campo) .

Para avanzar entre las líneas del código, contamos con los siguientes
botones.

Single Step (F5) Æ Ejecuta una línea de código.
Execute (F6) Æ Ejecuta un bloque de código.
Return (F7) Æ Sale de un bloque de código.
Run (to Cursor) (F8) Æ Continua con la ejecución del programa
hasta encontrar otro Break-Point.

134

Si no queremos que nuestro programa se pare cada vez que lo
ejecutemos. Debemos reemplazar el Break-Point por un Break-
Point lógico.

Nos posicionamos en la línea donde queremos que pare el programa.
En el menú seleccionamos Utilities Æ Breakpoints Æ Set/Delete.
O si no presionamos Ctrl. + Shift + F12 o presionamos el botón

. Esto funciona de la misma manera que el BREAK-POINT con
la diferencia de que si reiniciamos el programa, el BREAK-POINT
desaparece. Este tipo de BREAK-POINT es muy útil cuando
tenemos que hacer un DEBUG en un programa que no podemos
modificar.

135

Felizmente, tenemos una forma de guardar los break-points lógicos
para un programa. Este es un truco que aprendí hace un par de años
en el SDN ( http://sdn.sap.com ).

Cuando estamos en el Debugger, nos vamos al menú, y
seleccionamos Debugging Æ Sessions.

136

En esta pantalla podemos guardar un grupo de Break-Points
lógicos, los cuales se almacenan por defecto durante un mes.
Podemos cargarlos la próxima vez que ejecutemos el programa,
podemos extender su estadía por una semana más o podemos
eliminarlos.
Finalmente, la última manera para hace DEBUG a un programa, es
escribir /H en la barra de menú y presionar Enter.

Luego de eso, al ejecutar, entraremos al Debugger, aunque al del
programa que ejecuta los programas...Con un poco de paciencia
llegaremos a nuestro propio programa.

137

Programas de ejemplo

Decimal a Binario

REPORT ZDUMMY_PRIMER_PROGRAMA
NO STANDARD PAGE HEADING.

*=====================================================*
* DECLARACION DE VARIABLES *
*=====================================================*
DATA: SUMA_TEXT(50) TYPE C,
SUMA TYPE I,
EXPONENTE TYPE I,
FLAG TYPE C.

*=====================================================*
* SELECTION-SCREEN *
*=====================================================*
SELECTION-SCREEN BEGIN OF BLOCK DEC_TO_BIN WITH FRAME.
PARAMETERS:
P_NUMERO TYPE I.
SELECTION-SCREEN END OF BLOCK DEC_TO_BIN.

138

*=====================================================*
* START-OF-SELECTION *
*=====================================================*
START-OF-SELECTION.
PERFORM INICIALIZAR.
PERFORM CALCULAR_BINARIO USING P_NUMERO
CHANGING SUMA_TEXT.

IF FLAG EQ SPACE.
PERFORM IMPRIMIR.
ENDIF.

*&----------------------------------------------------*
*& Form INICIALIZAR *
*&----------------------------------------------------*
FORM INICIALIZAR.

SUMA = 0.
EXPONENTE = 1.

ENDFORM. " INICIALIZAR

*&----------------------------------------------------*
*& Form CALCULAR_BINARIO *
*&----------------------------------------------------*
FORM CALCULAR_BINARIO USING P_NUM
CHANGING P_SUM.

DATA: DIGITO TYPE I,
NUMERO TYPE I.

NUMERO = P_NUM.

139

EXPONENTE = EXPONENTE * 10. ENDFORM. ENDWHILE. CONDENSE P_SUM NO-GAPS. DIGITO = NUMERO MOD 2. FLAG = 'X'. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5.5 SUMA_TEXT. ENDIF. " CALCULAR_BINARIO *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. WRITE:/ 'El número binario de'. WHILE NUMERO GT 0. ENDCATCH. " IMPRIMIR Este programa convierte un número decimal a binario. ENDFORM. e incluye un elemento muy interesante.25 P_NUMERO. NUMERO = NUMERO DIV 2. el CATCH. SUMA = SUMA + DIGITO * EXPONENTE. P_SUM = SUMA. IF SY-SUBRC = 5. WRITE / 'Error de cálculo'. WRITE:/ 'es:'. 140 .

lo que queremos es que el ABAP capture cualquier error de tipo aritmético. ENDWHILE. por lo tanto utilizamos ARITHMETIC_ERRORS. WRITE / 'Error de cálculo'. 141 . Antes de imprimir. EXPONENTE = EXPONENTE * 10. SUMA = SUMA + DIGITO * EXPONENTE. NUMERO = NUMERO DIV 2. WHILE NUMERO GT 0. P_SUM = SUMA. Si hay algún error el valor 5 se pasa a la variable del sistema SY- SUBRC. CONDENSE P_SUM NO-GAPS. Y además utilizamos una variable FLAG a la cual se le pasa el valor X. mostramos un mensaje de error. DIGITO = NUMERO MOD 2. Si SY-SUBRC es igual a 5. el código que convierte el decimal a un binario está encerrado entre las sentencias CATCH-ENDCATCH. por lo tanto: IF SY-SUBRC = 5. comprobamos el valor de esta variable para no imprimir si es que ha habido errores. ENDCATCH. Como podemos ver. ENDIF. En este caso. FLAG = 'X'. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5.

PERFORM IMPRIMIR. Colores en ABAP Este programa muestra las posibles combinaciones de colores que pueden generarse en ABAP. 142 . ENDIF. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: I TYPE I. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. IF FLAG EQ SPACE.

COL(15) TYPE C. WHEN 5. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. 48 'INVERSE'. WHEN 7. WHEN 3. SY-VLINE. COL = 'COL_NEGATIVE '. SKIP 2. AT 7 SY-VLINE. COL = 'COL_TOTAL '. WRITE:/9 'INTESIFIED ON'. WRITE: /(4) I. WHEN 0. *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. PERFORM IMPRIMIR. FORMAT INTENSIFIED COLOR = I. WHEN 6. COL = 'COL_KEY '. ENDCASE. WHEN 2. COL = 'COL_NORMAL '. WHILE I < 8. CASE I. 27 'INTENSIFIED OFF'. 143 . COL = 'COL_POSITIVE '. COL. COL = 'COL_BACKGROUND '. COL = 'COL_HEADING '. COL = 'COL_GROUP '. WHEN 4. WHEN 1.

" IMPRIMIR Lenguajes y Programas REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TYPES * *=====================================================* 144 . COL INVERSE. ENDFORM. I = I + 1. ENDWHILE. SY-VLINE. *=====================================================* * DECLARACION DE INCLUDES * *=====================================================* INCLUDE <ICON>. COL INTENSIFIED OFF.

NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: ICONO TYPE STRING. *&----------------------------------------------------* *& Form SELECCIONAR_DATOS * *&----------------------------------------------------* 145 . PERFORM SELECCIONAR_DATOS.TYPES: BEGIN OF TY_PROGRAMAS. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. END OF TY_PROGRAMAS. PERFORM IMPRIMIR_DATOS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS.

25 'Programa'. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). WHEN 'SCRIPT'.15 'Entorno'. FORMAT COLOR OFF. 146 . 40 'Icono'. WRITE:/1 <FS_PROGRAMAS>-NOMBRE. 15 <FS_PROGRAMAS>-ENTORNO. 25 <FS_PROGRAMAS>-NOM_PROG. " SELECCIONAR_DATOS *&----------------------------------------------------* *& Form IMPRIMIR_DATOS * *&----------------------------------------------------* FORM IMPRIMIR_DATOS. FORMAT COLOR 5. ICONO = ICON_WD_WEB_PROJECT. WHEN 'WEB'. WHEN 'DESKTOP'. ENDFORM. ICONO = ICON_FOLDER.FORM SELECCIONAR_DATOS. WRITE:/1 'Lenguaje'. SKIP 1. ICONO = ICON_HISTORY. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. CASE <FS_PROGRAMAS>-ENTORNO.

de estamos mostrando un icono que representa a cada tipo de lenguaje. 25 <FS_PROGRAMAS>-NOM_PROG. WRITE: 40 ICONO. ENDLOOP. Para esto. WRITE:/1 <FS_PROGRAMAS>-NOMBRE. debemos incluir un subprograma llamado <ICON> con la palabra reservada INCLUDE. WHEN 'SCRIPT'. con la particularidad. WHEN 'WEB'. ENDLOOP. Gracias a este include. ICONO = ICON_FOLDER. ENDCASE. ICONO = ICON_HISTORY. WHEN 'DESKTOP'. Simplemente utilizando un CASE- 147 . WRITE: 40 ICONO. Declaramos una variable de tipo STRING llamada ICONO. ENDCASE. a la cual vamos a asignarle las constantes de iconos que obtenemos de la tabla ICON (Campo Name). 15 <FS_PROGRAMAS>-ENTORNO. ENDFORM. podemos llamar a cualquier icono de la tabla ICON. ICONO = ICON_WD_WEB_PROJECT. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. CASE <FS_PROGRAMAS>-ENTORNO. " IMPRIMIR_DATOS Este programa es muy parecido al que hicimos alguna páginas antes.

*=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: X_LINES TYPE STRING. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* 148 . Manejo de Cadenas de Texto En este programa vamos a hacer algunas funciones que no son parte de la sintaxis de ABAP (Aunque pueden utilizarse con Objetos como veremos más adelante).ENDCASE sabemos que valores asignar a la variable ICON para luego simplemente imprimirlo.

*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. 149 . *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK DEC_TO_BIN WITH FRAME. PERFORM IMPRIMIR USING TEXTO. PERFORM FILL_RIGHT_CHARACTERS USING '*' CHANGING TEXTO. PERFORM INICIALIZAR. V_LONG TYPE I.DATA: T_TABLE TYPE STANDARD TABLE OF X_LINES. AUX_TEXT(30) TYPE C. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: TEXTO(30) TYPE C. SELECTION-SCREEN END OF BLOCK DEC_TO_BIN. PARAMETERS: P_TEXTO(20) TYPE C. V_LEN TYPE I. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_TABLE> LIKE LINE OF T_TABLE.

150 . PERFORM INICIALIZAR. WRITE:/ <FS_TABLE>. PERFORM REVERSE_STRING USING TEXTO. ENDFORM. PERFORM IMPRIMIR USING TEXTO. PERFORM IMPRIMIR_TABLA TABLES T_TABLE. PERFORM IMPRIMIR USING TEXTO. PERFORM CAPITALIZE_LETTERS CHANGING TEXTO. PERFORM INICIALIZAR. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. TEXTO = P_TEXTO. SKIP 1. PERFORM INICIALIZAR. LOOP AT T_TAB ASSIGNING <FS_TABLE>. "INICIALIZAR *&----------------------------------------------------* *& Form IMPRIMIR_TABLA * *&----------------------------------------------------* FORM IMPRIMIR_TABLA TABLES T_TAB. PERFORM SPLIT_LONG_TEXT TABLES T_TABLE USING TEXTO.

CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. ENDFORM. "FILL_RIGHT_CHARACTERS 151 .V_LEN. DO V_LEN TIMES. "INICIALIZAR *&----------------------------------------------------* *& Form imprimir * *&----------------------------------------------------* FORM IMPRIMIR USING L_TEXTO. ENDFORM. WRITE:/ TEXTO. * *-----------------------------------------------------* FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. ENDDO. V_LEN = STRLEN( L_TEXTO ). DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE. "imprimir *&----------------------------------------------------* *& Form FILL_RIGHT_CHARACTERS * *&----------------------------------------------------* * Llena una cadena con caracteres a la derecha. ENDFORM. V_LEN = V_LONG . ENDLOOP.

"CAPITALIZE_LETTERS 152 . SHIFT L_TEXTO LEFT DELETING LEADING SPACE. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. TRANSLATE AUX_TEXT TO UPPER CASE. CLEAR L_TEXTO. ENDLOOP. ENDFORM. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE. TRANSLATE L_TEXTO TO LOWER CASE. CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. * *-----------------------------------------------------* FORM CAPITALIZE_LETTERS CHANGING L_TEXTO. V_LONG = V_LONG . V_LONG = STRLEN( <FS_TABLE> ). AUX_TEXT = <FS_TABLE>+0(1).*&----------------------------------------------------* *& Form CAPITALIZE_LETTERS * *&----------------------------------------------------* * Capitaliza un texto dado.1. LOOP AT T_TABLE ASSIGNING <FS_TABLE>.

DELETE T_TAB INDEX V_LEN. CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE = L_TEXTO DELIMITER = SPACE TABLES OUT_LINES = T_TAB EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. ENDFORM. DESCRIBE TABLE T_TAB LINES V_LEN. "SPLIT_LONG_TEXT 153 .*&----------------------------------------------------* *& Form SPLIT_LONG_TEXT * *&----------------------------------------------------* * Corta un texto largo en varios registros de * * una tabla * *-----------------------------------------------------* FORM SPLIT_LONG_TEXT TABLES T_TAB USING L_TEXTO.

154 . DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE.*&----------------------------------------------------* *& Form REVERSE_STRING * *&----------------------------------------------------* * Invierte una cadena * *-----------------------------------------------------* FORM REVERSE_STRING CHANGING L_TEXTO. ENDFORM. FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING = L_TEXTO LANG = SY-LANGU IMPORTING RSTRING = L_TEXTO EXCEPTIONS TOO_SMALL = 1 OTHERS = 2. Veamos cada uno de ellos. V_LEN = STRLEN( L_TEXTO ). "REVERSE_STRING En este programa tenemos varios FORMS y cada uno realiza una tarea en particular.

Utizamos un DO para ejecutar un bucle un número V_LEN de veces y concatenamos el texto con el carácter de relleno. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. ENDFORM. es decir. Y luego utilizamos DESCRIBE FIELD LENGTH IN CHARACTER MODE para determinar la longitud pero sin contar los espacios en blanco. la longitud con espacios menos la longitud sin espacios. restamos la longitud de V_LONG menos V_LEN. En la variable V_LEN. V_LONG = STRLEN( <FS_TABLE> ). LOOP AT T_TABLE ASSIGNING <FS_TABLE>. en este caso el ‘*’. FORM CAPITALIZE_LETTERS CHANGING L_TEXTO.V_LEN. ENDDO. DO V_LEN TIMES. TRANSLATE L_TEXTO TO LOWER CASE. V_LEN = V_LONG . "FILL_RIGHT_CHARACTERS Utilizamos STRLEN para determinar la longitud total del texto (Incluyendo espacios en blanco). CLEAR L_TEXTO. CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. 155 .

Concatenamos el primer caracter mas los demás caracteres de la cadena. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE. 156 . enviamos las subcadenas a una tabla interna. leer un caracter empezando desde la primera posición. CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. Utilizando TRANSLATE TO UPPER CASE. ENDLOOP. FORM SPLIT_LONG_TEXT TABLES T_TAB USING L_TEXTO. convertimos la cadena a Minúsculas utilizando el TRANSLATE TO LOWER CASE. convertimos a Mayúsculas el caracter que hemos leído. "CAPITALIZE_LETTERS Primero. para poder modificarlos uno por uno.1. SHIFT L_TEXTO LEFT DELETING LEADING SPACE. TRANSLATE AUX_TEXT TO UPPER CASE. Leemos el primer carácter utilizando +0(1) que significa. V_LONG = V_LONG . AUX_TEXT = <FS_TABLE>+0(1). Con STRLEN determinamos la longitud del Field-Symbol y le restamos uno. ENDFORM. Finalmente concatenamos todos las subcadenas en una cadena más grande con los letras ya capitalizadas. Luego con un SPLIT AT SPACE INTO TABLE.

pero quería que vieran como se utilizan los módulos de funciones. El módulo de funciones que utilizamos tiende a tomar los espacios en blanco y agregarlos como longitud total de la cadena. CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE = L_TEXTO DELIMITER = SPACE TABLES OUT_LINES = T_TAB EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. "SPLIT_LONG_TEXT Utilizamos la función RSDG_WORD_WRAP para partir una cadena en subcadenas y enviarlas a una tabla. utilizando un DESCRIBE TABLE LINES para poder determinar cuantas líneas tiene nuestra tabla interna. Al final. es por eso que sabiendo cuantas líneas tienen la tabla interna. Podríamos haber utilizado un SPLIT INTO TABLE. podemos eliminar la última sin tener problemas. DESCRIBE TABLE T_TAB LINES V_LEN. ENDFORM. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING = L_TEXTO 157 . FORM REVERSE_STRING CHANGING L_TEXTO. DELETE T_TAB INDEX V_LEN.

158 . LANG = SY-LANGU IMPORTING RSTRING = L_TEXTO EXCEPTIONS TOO_SMALL = 1 OTHERS = 2. ENDFORM. "REVERSE_STRING Utilizamos el módulo de funciones STRING_REVERSE para invertir el orden de la cadena.

Como por ejemplo. para Certificados de Trabajo. Facturas. Creando un formulario Para poder crear formularios.SapScript Introducción Uno de los puntos fuertes que tiene el ABAP. aunque lo último depende más que nada de la impresora o de software adicional para poder mostrarlos correctamente. Notificaciones de Empresa. debemos ingresar a la transacción SE71 (Form Painter). que pueden ser utilizados por ejemplo. etc. Su creación no es complicada y permite hacer varias cosas interesantes. es la posibilidad de crear formularios. incluir logos o imprimir códigos de barras. 159 .

. puede hacerlo con muchos idiomas predefinidos (Bueno.En el campo formulario. En realidad...). Francés. Italiano. el idioma en el cual queremos crearlo (Bastante simple no?). puesto que cuando uno ingresa a NetWeaver. ingresamos el nombre de nuestro formulario y en el campo idioma. Español..La versión completa del NetWeaver incluye entre muchos otros. puesto que solamente permite Alemán e Inglés. 160 . el idioma se utiliza para poder crear de una manera más sencilla las traducciones. Presionamos el botón Create (Crear) para poder crear nuestro formulario. no esta versión.

Luego de esto. deberemos ingresar a la sección de Basic Settings (Parametrizaciones Básicas) con el siguiente botón . deberemos ingresar un texto que describa brevemente al formulario. 161 .En esta ventana.

Como este formulario es nuevo.En esta ventana. necesitamos crear un nuevo elemento. Para poder crearla. se nos exige especificar una Página Inicial y un Párrafo por defecto. presionando el siguiente botón . Como vemos. 1.Crear una página inicial Ingresamos a la opción Pages (Páginas). ninguno de estos existe. Esto podemos hacerlo de 3 162 .. no existe ninguna página. por lo cual deberemos crearlos.

con el menú de la transacción o presionando SHIFT + F6. Menú de clic derecho Menú de transacción Cuando creamos un nuevo elemento. el sistema nos mostrará la siguiente ventana: 163 .formas. Con un clic derecho.

deberemos hacer clic en el botón Page Windows (Ventanas de Página) .En Page (Página) ingresaremos el nombre de la página que queremos crear y en Description (Description). simpre la página principal será llamada MAIN. Luego de haber creado el elemento. Por convención. una descripción de la página. Para poder crear una ventana. deberemos asignarle una ventana..Crear una ventana en una página Después de haber creado nuestra página. 164 . que es el espacio en el cual vamos a trabajar para poder crear nuestros formularios. Una página puede tener muchas ventanas. podremos verlo como se muestra a continuación. Y un formulario puede tener muchas páginas. 2.

En esta ventana. se nos muestra una ventana por defecto. 165 . creada cuando creamos la página. Si queremos crear ventanas adicionales. Cuando creamos el nuevo elemento. Es decir. deberemos de crear un nuevo elemento. se nos muestra la siguiente ventana.Y seguir un procedimiento similar al de la creación de la página.

Por ejemplo: Para poder definir las propiedades de las ventanas. Por cada Ventana Página que creemos. deberemos llenar sus atributos en la siguiente ventana (Que está al final de la pantalla).deberemos hacer clic en el botón Windows (Ventanas) y crear un nuevo elemento. 166 . simplemente deberemos de hacer un doble clic sobre ella. Para poder elegir la ventana. tenemos disponibles los siguientes sistemas de medición.

etc. su asignación (Con el botón Outline ). así como el tipo de letra (Con el botón Font ).Crear párrafo por defecto Para crear un nuevo párrafo. deberemos hacer clic en el botón Paragraph Formats (Formatos de Párrafo) ..3. los tabuladores (Con el botón Tabs ). Se nos mostrará la siguiente ventana: Aquí deberemos asignarle un nombre al nuevo párrafo (Por convención utilizamos ST). 167 .

168 . Y luego en el botón parametrizaciones básicas . deberemos regresar a la configuración de cabecera para poder finalizar con las parametrizaciones básicas. simplemente hacemos un clic en el botón Header (Cabecera) o presionamos F5.Una vez que hemos creado la página y el párrafo por defecto. Es importante indicar cual es la página principal. Para esto.

TOA_DARA.ITCPP. *=====================================================* * DECLARACION DE TABLAS * *=====================================================* TABLES: ZPROGRAMAS. Este programa llama al formulario y le pasa toda la información necesaria. 169 . esta debe provenir de un programa. que vamos a crear un programa bastante sencillo para utilizar como ejemplo. Creando un programa de impresión Para que un SAPScript pueda mostrar información. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. Es por eso.Una vez que hemos terminado.ITCPO. debemos grabar el formulario y activarlo mediante el menú.

*=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. PERFORM INICIALIZAR. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_ZPROGRAMAS. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: V_FORM(14) TYPE C. V_SCRIPT. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. 170 . SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG.

*&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. ENDFORM. IF V_SCRIPT EQ SPACE. PERFORM ABRIR_SAPSCRIPT. ITCPO-TDDELETE = '*'. "INICIALIZAR *&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SAPSCRIPT. ITCPO-TDLIFETIME = '7'. V_FORM = 'ZDUMMY_FORM'. CALL FUNCTION 'OPEN_FORM' EXPORTING 171 . ITCPO-TDPREVIEW = 'X'. ITCPO-TDIMMED = '*'. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG.*=====================================================* * END-OF-SELECTION * *=====================================================* END-OF-SELECTION.

172 . CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. ENDIF. FORM = V_FORM LANGUAGE = 'S' OPTIONS = ITCPO ARCHIVE_INDEX = TOA_DARA DEVICE = 'PRINTER' DIALOG = 'X' EXCEPTIONS CANCELED = 01. ENDLOOP. CALL FUNCTION 'START_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S'. V_SCRIPT = 'X'. IF SY-SUBRC NE 0. LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'MAIN' WINDOW = 'MAIN' EXCEPTIONS OTHERS = 01. EXIT. ENDIF.

IF V_SCRIPT NE SPACE. ITCPO-TDPREVIEW = 'X'. ENDIF. salida inmediata. Las tablas ITCPO.TOA_DARA. • Parámetro impresión. borrar tras salida. V_SCRIPT.ITCPP. • Parámetro impresión. DATA: V_FORM(14) TYPE C. • Parámetro impresión.ITCPO. 173 . La variable V_FORM contendrá el nombre del formulario. ENDFORM. TOA_DARA y ITCPP son necesarias para poder ejecutar el SAPScript. CALL FUNCTION 'CLOSE_FORM'. ITCPO-TDLIFETIME = '7'. "ABRIR_SAPSCRIPT Analicemos un poco el programa. mientras que la variable V_SCRIPT nos sirve para determinar si el formulario está activo o no. ITCPO-TDIMMED = '*'. TABLES: ZPROGRAMAS. tiempo de permanencia en SPOOL. ITCPO-TDDELETE = '*'.

IF V_SCRIPT EQ SPACE. EXIT. CALL FUNCTION 'OPEN_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S' OPTIONS = ITCPO ARCHIVE_INDEX = TOA_DARA DEVICE = 'PRINTER' DIALOG = 'X' EXCEPTIONS CANCELED = 01. ENDIF. V_SCRIPT = 'X'. • Visualización de impresión. IF SY-SUBRC NE 0. Iniciamos la ejecución del formulario. ENDIF. CALL FUNCTION 'START_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S'. 174 . para esto utilizamos el módulo de funciones OPEN_FORM. entonces debemos abrir el formulario. Si la variable V_SCRIPT está vacía.

IF V_SCRIPT NE SPACE. ENDIF. CALL FUNCTION 'CLOSE_FORM'. ENDLOOP. Hacemos un LOOP a la tabla interna T_ZPROGRAMAS y asignamos los valores al Field-Symbol <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW = 'MAIN' EXCEPTIONS OTHERS = 01. 175 . Con el módulo de funciones END_FORM indicamos que hemos terminado de utilizar la ventana. LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. cerramos el formulario con el módulo de funciones CLOSE_FORM. CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. Si la variable V_SCRIPT no está vacía. llamamos al módulo de funciones WRITE_FORM que lo que hace es llamar a la ventana de nuestro formulario. Por cada vuelta del LOOP.

Debemos ingresar al menú Settings (Opciones) y presionar Form Painter.Una vez creado el programa. Simplemente. contamos con un editor gráfico. Para poder acceder. Diseñando el formulario Además de la forma que ya vimos para crear nuestro formulario. 176 . debemos marcar el check Graphical Form Painter (Form Painter gráfico). podemos regresar a nuestro formulario para poder comenzar a llenar los datos que queremos mostrar cuando sea ejecutado. deberemos ingresar a la transacción SE71 (Form Painter).

simplemente debemos desmarcar el checkbox de Form Painter gráfico. deberemos presionar el botón Text (Texto) . Para poder asignar el código a la ventana. podemos especificar el tamaño y la disposición de las distintas ventanas que creemos en nuestro formulario. 177 . En este editor gráfico.Ingresamos a nuestro formulario y presionamos el botón Layout (Diposición) . Para volver al modo de edición por defecto.

dejando el menú por defecto.En esta ventana. o llamandolo explicítamente como ST Párrafo por defecto. Si los 178 . podemos llamar al tipo de párrafo por defecto de dos maneras. podremos escribir el código para llamar a los campos que definimos en nuestro programa (Es decir. a los campos de la tabla interna) y mostrarlos al momento de imprimir el formulario. Como podemos ver. veremos que hemos escrito texto y el nombre de los campos del field-symbol dentro de ampersands (&). En la parte de código.

haremos lo siguiente. Una vez ahí. Luego hacemos clic en el botón Paragraph Formats (Formatos de Párrafo) . y seleccionamos el formato de caracter que creamos. de vuelta en nuestra ventana. 179 . Seleccionamos el texto que queremos en negrita. hacemos clic en Character Formats (Formatos de Caracter) . no podríamos llamar a las variables de nuestro programa dentro del formulario. Ahora. Supongamos que queremos que los textos se muestren en negrita y los valores como un texto normal. Primero que nada.ampersand. debemos grabar nuestro código y retroceder con el botón BACK (Retroceder) o presionar F3.

debemos cambiar de editor. 180 . vamos a crear una caja para que se muestre el nombre del programa. Para esto. Y de paso eliminamos cualquier código adicional que haya agreagado el SAPScript. puesto que debemos crear la caja utilizando código. (Yo recomiendo siempre utilizar este editor).Para terminar.

Elegimos LP01 como impresora por defecto y presionamos Print Preview (Vista previa de 181 . Al momento de ejecutar el programa. y que el borde sea de 10 TW. puesto que al tratarse de un formulario. que tenga 50 milimetros de ancho y 5 de alto. activamos y ejecutamos nuestro programa. de que además agregamos la línea /E ITEM Puesto que ITEM va a ser nuestro ELEMENTO dentro del ventana. se nos muestra una ventana de impresión.Creamos una caja que empieza en la posición 0. pero un elemento. Grabamos. Se habrán dado cuenta. debemos imprimirlo para poder visualizarlo. Una ventana se puede llamar una sola vez. varias veces.

En el editor. Los datos son correctos. sino simplemente comprobar que está bien hecho el formulario. Puesto que no queremos imprimirlo. agregamos YPOS &POS& MM. pero los textos están muy juntos los unos de los otros. es decir indicamos cual va a ser la posición Y de la caja. 182 .impresión). En este caso. veamos como resolvemos esto. además la caja de texto simpre está en el mismo lugar. va a ser un valor variales indicado por &POS&.

V_SCRIPT. luego de haber impreso el contenido del elemento. V_FORM = 'ZDUMMY_FORM'. Inicializamos la variable POS en 0. ENDLOOP. debemo también agregar algunas cosas en el programa. LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. Para que esto funcione correctamente. ya podemos imprimir nuevamente el formulario. POS TYPE STRING.Además. Ahora. DATA: V_FORM(14) TYPE C. agregamos una línea en blanco. 183 . POS = 0. En cada iteración del LOOP. POS = POS + 13. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW = 'MAIN' EXCEPTIONS OTHERS = 01. Agregamos la variable POS de tipo STRING. aumentamos el valor de la variable POS en 13.

Para terminar. podríamos crear una tabulación. 184 . Nos vamos a Paragraph Formats . con lo cual el texto ID Programa quedaría más centrado en la caja. Seleccionamos nuestro párrafo por defecto y presionamos el botón Tabs (Tabuladores) .

antes del texto. Grabamos.Creamos una tabulación de 5 MM con alineación a la izquierda. activamos y ejecutamos el programa. 185 . Regresamos al Layout y cambiamos el formato del editor.. escribimos . Para agregar un tabulador.

ingresamos al transacción SE71 (Form Painter). Y elegir Utilities Æ Activate Debugger (Utilidades Æ Activar Debugger). Para activar el Debugger. Esto es bastante sencillo.No es de las mejores herramientas de SAP.. al ejecutar el programa. veremos la siguiente ventana.. y claro. aunque no mucha gente lo sepa. Ahora. puesto que no es una opción que esté muy a la vista. 186 .Debugger en SAPScript Hay que veces que necesitamos hacer un Debug a un SAPScript.

podemos ver cual es el contenido de las variables. puesto que nos permite recorrer el formulario línea por línea (En el caso de los textos caracter por caracter). Por lo general se utiliza el botón Single Step (Paso sencillo). 187 .Simplemente presionamos OK para poder continuar con el Debugger. Con esto.

SmartForms Introducción Los SmartForms.. que no se incluyen en este libro) que reemplazan a los para algunos obsoletos formularios SAPScript..Yo siempre he sido un fanático acerrimo del SAPScript.. son la nueva generación de formularios (Ok.. Creando un estilo Para crear un estilo debemos ingresar a la transacción SMARTFORM y seleccionar el radio button Style (Estilo). 188 . En realidad es cuestión de gustos.No tan nuevas si consideramos a los Adobe Forms.

vamos a crear nuestro párrafo por defecto. 189 .Lo nombramos ZTEST_ESTILO y presionamos el botón Create (Crear) . Debemos crear un nuevo nodo en la opción Paragraph Format (Formato de Párrafo). tal como lo hicimos en el SAPScript. En esta ventana.

tamaño e inclusive color (Claro. Y llenamos su descripción. Tipo de Letra.. 190 .. es lo que menos abunda en las empresas).Llamemos ST a este nuevo nodo. que seamos realistas.para impresoras a colores.

191 . hacemos doble clic en Header Data (Datos de Cabecera). Y asignamos nuestro párrafo por defecto.Cuando hemos terminado.

debemos asignar el estilo que creamos. 192 . activamos y salimos a la pantalla inicial. Creando un Formulario Creamos nuestro primer SmartForm llamado ZPRIMER_SMARTFORM. En la pestaña Output Options (Opciones de Salida). grabamos.Cuando terminamos.

así que podemos dejarla así. Clic derecho en MAIN. necesitamos una página y una ventana. Como vemos %PAGE1 está creada por defecto. debemos crear un texto de la siguiente manera. Create Æ Text (Crear Æ Texto). 193 .Al igual que en SAPScript. Para poder escribir en esta ventana. o asignarle un nuevo nombre. Lo mismo ocurre con la ventana MAIN.

veremos una pantalla como esta. 194 . Llenamos el texto tal como hicimos con el SAPScript.Cuando creamos el texto.

Para poder utilizar las variables dentro del SmartForms. debemos definir algunas variables globales. asignamos una tabla interna. Aquí creamos una estructura intermedia que recoge los datos del SmartForms y los almacena para poder mostrarlos en el formulario. Ahora nos vamos a Global Definitions (Definiciones Globales) y luego a la pestaña Global Data (Datos Globales). En la pestaña Tables (Tablas). para esto nos vamos a Form Interface (Interface de Formulario). 195 .

dentro del LOOP. Una vez creado. 196 .Debemos crear un LOOP para poder asignar los valores de la tabla de parámetro a la tabla intermedia. debemos mover nuestro texto.

197 . *=====================================================* * DECLARACION DE TABLAS * *=====================================================* TABLES: ZPROGRAMAS. debemos crear el programa que va a llamar a nuestro SmartForms. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS.En el LOOP debemos asignar los datos de la tabla hacia la tabla intermedia. Creando un programa de impresión Ahora.

PERFORM ABRIR_SMARTFORMS.*=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: MODULO_FUNCION TYPE RS38L_FNAM. 198 . SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. *=====================================================* * END-OF-SELECTION * *=====================================================* END-OF-SELECTION. PERFORM INICIALIZAR. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.

ENDFORM. "INICIALIZAR *&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SMARTFORMS.*&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG. CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME = 'ZPRIMER_SMARTFORM' IMPORTING FM_NAME = MODULO_FUNCION EXCEPTIONS NO_FORM = 1 NO_FUNCTION_MODULE = 2 OTHERS = 3. CALL FUNCTION MODULO_FUNCION TABLES T_PROGRAMAS = T_ZPROGRAMAS EXCEPTIONS 199 .

ENDFORM. DATA: MODULO_FUNCION TYPE RS38L_FNAM. los SmartForms se generan como módulos de funciones. FORMATTING_ERROR = 1 INTERNAL_ERROR = 2 SEND_ERROR = 3 USER_CANCELED = 4 OTHERS = 5. "ABRIR_SAPSCRIPT Revisemos el programa. Porque hacemos esto? Muy simple. por lo tanto. 200 . CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME = 'ZPRIMER_SMARTFORM' IMPORTING FM_NAME = MODULO_FUNCION EXCEPTIONS NO_FORM = 1 NO_FUNCTION_MODULE = 2 OTHERS = 3. Declaramos una variable llamada MODULO_FUNCION del tipo RS38L_FNAM. necesitamos una variable que tenga el mismo tipo que los Módulos de Funciones.

Utilizamos el módulo de funciones SSF_FUNCTION_MODULE_NAME para poder obtener el nombre del módulo de funciones que generó el SmartForms. hacemos una llamada dinámica al SmartForms y pasamos los parámetros necesarios. Grabamos. 201 . se nos mostrará una pantalla de parámetros de impresión. activamos y ejecutamos el programa. CALL FUNCTION MODULO_FUNCION TABLES T_PROGRAMAS = T_ZPROGRAMAS EXCEPTIONS FORMATTING_ERROR = 1 INTERNAL_ERROR = 2 SEND_ERROR = 3 USER_CANCELED = 4 OTHERS = 5. Con la variable MODULO_FUNCION. Ejecutando el formulario Al igual que en el SAPScript. en este caso la tabla interna T_ZPROGRAMAS.

202 . impresa en color azul.Tenemos nuestra lista. Si les parece que está un poco abajo. es cuestión simplemente de ajustar las propiedades del texto.

Para esto. 203 .Crear una tabla Si bien el formulario se ve bien. debemos aprovechar una de las opciones más interesantes que nos brindan los SmartForms.. (Si imaginan hacer algo así como multiples box’s en SAPScript?). vamos a modificar un poco nuestro programa.Utilizar una tabla para mostrar la información. Eliminamos el LOOP que habíamos creado y creamos una nueva tabla..

Lo cual nos servirá para definir los componentes de la tabla. debemos hacer clic en el botón Details (Detalles) . asignar la tabla de parámetro a nuestra tabla intermedia.En la pestaña DATA (Datos) debemos hacer lo mismo que habíamos hecho en el LOOP. 204 . para poder asignar un nombre de línea. En la pestaña Table (Tabla).

205 .Para crear la cabecera de nuestra tabla. nos posicionamos en Header y con un clic derecho escogemos Create (Crear) Æ Table Line (Línea de Tabla). Escogemos el tipo de línea que hemos creado.

dibujamos una línea vertical (Con esto creamos automáticamente un %CELL2). una sola celda. solamente tenemos un %CELL1 es decir. 206 . pero nosotros necesitamos dos.Como veremos. debemos agregar en cada uno un Texto para poder mostrar el título de cada campo. así que vamos al nodo principal %TABLE1 a la pestaña Table y dentro del Formulario gráfico. Como tenemos reservados los espacios para dos campos.

asignamos los textos y pasamos la variables &T_AUX_PROGRAMAS- ID_PROG& y &T_AUX_PROGRAMAS-NOM_PROG& tal como hicimos con el SAPScript. es decir. creamos una Línea de Tabla.Seguimos el mismo procedimiento para Main Area (Area Principal). estamos listos para ejecutar el programa. 207 . Con esto.

hacemos clic sobre el botón Draw Lines and Columns (Dibujar líneas y columnas) . En el nodo principal de la tabla.Si queremos que se note que hemos utilizado una tabla. Presionamos el botón Select Pattern (Seleccionar Patrón) . 208 . hacemos lo siguiente. Seleccionamos los campos de nuestra línea de tabla (Utilizando la tecla Control). para deshabilitarlo.

209 .El botón Display Framed Patterns (Mostrar patrones con marco) . Y seleccionamos el tipo que se muestra en la figura.

Cuando ejecutamos el formulario. 210 . lo veremos de la siguiente manera.

son los menús. Screen Painter Para poder crear Dynpros o pantallas en ABAP. radio buttons o tablas. Una adición importante y necesaria a los Dynpros. además de los reportes. Estos son muy útiles cuando queremos crear programas con mayor capacidad de procesamiento gráfico. en los cuales podemos incluir diversos elementos tales como cajas de textos. creados con el Menu Painter. deberemos ingresar a la transacción SE51 (Screen Painter).Screen Painter y Menu Painter Introducción En ABAP. 211 . podemos crear pantallas o dynpros.

ya que podemos tener muchas pantallas relacionadas entre si. Es importante que el programa exista. deberemos hacer clic en el botón Create (Crear) . no vamos a crear un programa nuevo. 212 . puesto que simplemente vamos a asociarle una pantalla. establecemos el número de la pantalla.En el campo Program (Programa) ingresaremos el nombre del programa en el cual se va a utilizar el dynpro. Aquí deberemos ingresar una descripción breve. O inclusive. y en el campos Screen Number (Número de Pantalla). que explique para que va a ser utilizada la pantalla. llamar a pantallas distintas dependiendo de una condición dada. Como en el caso de los programas.

En este caso. 213 . lo dejamos con el valor por defecto.En Screen Type (Tipo pantalla). debemos especificar que tipo de Dynpro queremos crear. debemos hacer clic en el botón Layout (Disposición) . por lo general utilizamos Normal. Los demás parámetros podemos dejarlos como están. En el caso de Next Screen (Siguiente pantalla). Para poder comenzar a diseñar nuestra pantalla. lo llenaremos solamente si es que luego de esta pantalla vamos a llamar a otra.

Permite crear un contenedor para los controles. 214 . Æ Casilla de Selección o Checkbox. Æ Botón de Selección o RadioButton. Æ Área SubScreen. Æ Control de fichas o Control de Tabuladores. Llamado también Tabla o Grilla. Æ Wizard de Table Control o Grilla.Controles del Screen Painter Æ Cursor que sirve para seleccionar y mover los controles dentro del dynpro. Permite colocar un Dynpro de tipo SubScreen dentro de otro Dynpro de tipo Normal. Permite crear este control mediante un ayudante paso a paso. Æ Wizard de control de Fichas o Control de tabuladores. Permite crear este control mediante un ayudante paso a paso. sirve para crear labels o etiquetas descriptivas. Æ Campo de Entrada/Salida. nos sirve tanto para recoger como para obtener datos. Æ Pulsador o Botón. Æ Campo de texto. Æ Table control. Æ Box.

215 . si la ejecución de la pantalla fue exitosa o errónea. Para poder crear cualquiera de estos controles. Æ Custom Control o Control Personalizado. Muy utilizados para programación en ABAP Objects. bastará con seleccionarlos y arrástrarlos hacia el espacio de nuestro dynpro. Nos permite crear elementos en tiempos de ejecución. es decir. Permite establecer el status de una pantalla. Æ Icono Status.

Por lo tanto utilizaremos el nombre ZPROGRAMAS-ID. Vamos a crear una caja de texto. creamos un control Text Field (Campo de Texto). vamos a hacer algo bastante sencillo. Una vez ingresado el nombre. en donde especificaremos el valor que queremos utilizar como filtro y en una tabla o grilla. Luego. al cual llamaremos TEXT_FILTRO y que tendrá como texto “Filtro”. obtenemos sus características y existe una relación directa con la Base de Datos). 216 . vamos a crear un control Input/Output Field (Campo de Entrada/Salida). por lo cual. al cual vamos a asociarlo con un campo de la base de datos. se nos mostrará el siguiente mensaje (Esto es porque estamos utilizando el nombre de una tabla y un campo.Ejemplo de Screen Painter Para este ejemplo. mostraremos los campos seleccionados en base a ese filtro. Primero.

Para poder acceder a las propiedades de este control. simplemente debemos hacer un doble clic.Deberemos hacer clic en Yes (Sí) para que nuestra caja de texto tome la referencia del campo ID de la tabla ZPROGRAMAS. 217 .

218 .

para cada campo que deseemos mostrar. 219 . debemos crear nuestra tabla con el control Table Control . deberemos utilizar un control Text Field y otro control Input/Output Field. se llamará TABLA.Ahora. Para poder crear los campos de nuestra tabla. Nuestra tabla.

220 . que vamos a crear en nuestro programa. Luego de haber creado nuestros controles en el Dynpro.Primero debemos crear el control Input/Output Field y luego el Text Field. debemos crear la lógica de proceso para nuestra pantalla. En este caso. llamada T_ZPROGRAMAS. debemos hacer clic en el botón Flow Logic (Flujo lógico) . Para esto. vamos a asociar los campos de nuestra tabla a una tabla interna. el primero T_ZPROGRAMAS-ID_PROG y el segundo T_ZPROGRAMAS-NOM_PROG. En este caso. es el programa control para el Dynpro. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. Ambos referenciando a un campo de una tabla. Esta tabla vamos a definirla en el programa ZDUMMY_PRIMER_PROGRAMA que en este caso.

debemos ingresar el siguiente código (Para esto. Dentro del MODULE STATUS_0100.Debemos descomentar ambos módulos y hacer doble clic en cada uno de ellos para que se autogeneren en el código fuente de nuestro programa de control y así poder utilizarlos. Con esto. simplemente hacemos doble clic en el texto STATUS_0100). simplemente leemos el contenido de la tabla interna T_ZPROGRAMAS y lo asignamos a cada campo de nuestra tabla. deberemos incluir el siguiente código marcado en rojo. Para poder llenar la tabla con los datos obtenidos en base al filtro. 221 .

nos avisan que el módulo STATUS_0100 no existe. nos pregunta si queremos crearlo en el programa fuente. Cuando el NetWeaver va a crear un nuevo módulo o función. vamos a crearlo en el programa principal. En este caso.En esta ventana. o queremos crear un INCLUDE (Es decir. un programa adicional que será llamado por el programa principal). Por lo tanto. debemos crearlo aceptando el mensaje. 222 .

podemos agregar el código necesario a nuestro programa. ID = ZPROGRAMAS-ID. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. * SET TITLEBAR 'xxx'.. Ahora. DATA: LINEAS TYPE I.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. ENDMODULE. TABLA-LINES = LINEAS.Eso es porque vamos a verlos más adelante. ID TYPE ZPROGRAMAS-ID. * SET PF-STATUS 'xxxxxxxx'. 223 . " STATUS_0100 OUTPUT Se darán cuenta de que los SET están comentados..

REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS WITH HEADER LINE. *=====================================================* * DECLARACION DE TABLAS * *=====================================================* TABLES: ZPROGRAMAS. CALL SCREEN '100'. ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. 224 . CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. DATA: LINEAS TYPE I.

CALL SCREEN '100'. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. TABLA-LINES = LINEAS. * SET TITLEBAR 'xxx'. ENDIF. * SET PF-STATUS 'xxxxxxxx'. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. START-OF-SELECTION. ENDMODULE. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. 225 . ENDMODULE. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. " USER_COMMAND_0100 INPUT Revisemos el código. Debemos crear un control llamado TABLA de tipo TABLEVIEW (Vista de Tabla) utilizando la pantalla 100. IF ID NE SPACE. En otras palabras.

ENDMODULE. * SET PF-STATUS 'xxxxxxxx'.debemos declarar por código. Finalmente. DATA: LINEAS TYPE I. ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. ENDIF. " STATUS_0100 OUTPUT Creamos dos variables. TABLA-LINES = LINEAS. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. * SET TITLEBAR 'xxx'. IF ID NE SPACE. 226 . LINEAS de tipo I e ID de tipo ZPROGRAMAS-ID. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. llamamos a la pantalla 100. MODULE STATUS_0100 OUTPUT. que hemos creado una tabla en la pantalla 100.

Seleccionamos todos los campos de la tabla ZPROGRAMAS siempre y cuando. Obtenemos la cantidad de líneas que hay en la tabla interna. el ID sea igual a nuestra variable ID. Si la variable ID no está vacía (Es decir. utilizando el comando DESCRIBE TABLE. significa que recogemos el valor de la caja de texto del dynpro y lo guardamos en una variable auxiliar. Para poder ejecutar el programa. 227 . entonces podemos continuar. le decimos cuantas líneas se deberían de mostrar en la tabla.Al pasar el valor de ZPROGRAMAS-ID a la variable ID. hemos ingresado un valor en la caja de texto). es decir. debemos activar tanto el Dynpro como el programa. Finalmente asignamos la variable LINEAS (Que contiene la cantidad de líneas de la tabla interna) al campo LINES de nuestra tabla TABLA.

228 . Si se fijan bien. Esto se debe a que no hemos asociado un menú a nuestra pantalla. veremos como funciona el programa. Por lo tanto debemos crear uno en la transacción SE41. se darán cuenta de que todos los botones en la barra de transacciones están deshabilitados.Si ingresamos el código de un lenguage.

Menu Painter Lo primero que debemos hacer. es crear un Status. En la ventana que nos muestra el NetWeaver. que en este caso. deberemos hacer clic en el botón Create (Crear) . va a ser el 100. dejemos el que viene por defecto. En cuanto al Status Type (Tipo de Status). como siempre. es decir Online Status (Status en línea). 229 . debemos ingresar un texto breve o descripción que nos indique para que se utilizará este menú. Para ello.

Una vez que aceptemos. 230 . solo nos va a importar esta sección. En la gran mayoría de los casos. Debemos hacer clic en este botón para poder expandirlo. se nos mostrará la siguiente pantalla.

Nuevamente. 231 . Con esto. Para poder agregarlo a nuestro programa. SET PF-STATUS '100'. descomentarla). nuestro menú está listo para utilizarse. Aquí debemos establecer que botones queremos habilitar y cuales son sus nombre de función. solo nos interesa esta sección. para este ejemplo. Ahora. debemos grabar y activar. simplemente deberemos incluir la siguiente línea (O más bien.

debemos incluir el siguiente código. CASE OK_CODE. para ello. ENDCASE. Con esto parecería ser suficiente. Aunque en este caso no es necesario.. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.. SET SCREEN 0. que queremos utilizar un menú creado por nosotros. deberíamos incluir el OK_CODE dentro de nuestro Dynpro.El SET PF-STATUS le dice a nuestro Dynpro.Pero no. " USER_COMMAND_0100 INPUT En este caso. DATA: OK_CODE TYPE SY-UCOMM. así que vamos a la transacción SE51. ENDMODULE.Aún debemos asignar las funciones que va a cumplir cada uno de los botones de nuestro menú. así que no hay mucho problema. La variable del sistema SY-UCOMM. los tres botones hacen lo mismo. MODULE USER_COMMAND_0100 INPUT. OK_CODE = SY-UCOMM. y ‘100’ es el número de dicho menú. determina que valor tiene el botón que ha sido presionado. CLEAR SY-UCOMM.. LEAVE SCREEN.. 232 . cuando tengamos más botones.

Escogemos Element list (Lista de elementos) y presionamos el

botón Change (Cambiar) .
Al final de la lista, agregamos el OK_CODE.

233

Grabamos, activamos y ejecutamos el programa.

Se darán cuenta de que el título de nuestro programa es SAP...Y este
es un título por defecto, así que vamos a crear uno más interesante.
Primero, debemos descomentar la siguiente línea.

SET TITLEBAR '100'.

Y luego, hacemos un doble clic.

234

Aceptamos y continuamos.

Agregamos un título, aceptamos...Y ahora viene una pequeña crítica
a SAP...Si queremos activar el título, debemos hacer una de dos
cosas...Ingresar a la SE41 y activar o sino, recompilar el código
fuente y activarlos juntos. Para mí, el título debería activarse cuando
aceptamos esta ventana...en fín...

235

Agregando componentes al ejemplo

Ahora que ya sabemos crear un Dynpro sencillo, vamos a mejorarlo
un poco, agregando un botón. Este botón se llamará PROCESAR y
tendrá el mismo texto.
Una vez creado, podemos hacer doble clic para modificar sus
propiedades.

Como podemos ver, los atributos del pulsador poseen dos campos
adicionales, que son Icon Name (Nombre de Icono) y Tooltip
(Información adicional). Para seleccionar el icono, simplemente

hacemos clic en el botón Choose Icon (Escoger Icono) .

236

Esta ventana nos muestra todos los iconos disponibles. El Tooltip,
no es más que el mensaje que aparece cuando situamos el mouse
sobre el componente.
El valor del FctCode (Function Code – Código de Función), es
sumamente importante, puesto que nos va a ayudar a activar el
evento relacionado al botón PROCESAR.

Como FctCode vamos a utilizar el mismo nombre del botón.
Dentro del programa, hacemos unos pequeños cambios.

237

MODULE USER_COMMAND_0100 INPUT.

DATA: OK_CODE TYPE SY-UCOMM.

OK_CODE = SY-UCOMM.
CASE OK_CODE.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
SET SCREEN 0.
LEAVE SCREEN.
CLEAR SY-UCOMM.
WHEN 'PROCESAR'.
PERFORM PROCESAR_DATOS.
ENDCASE.

ENDMODULE. " USER_COMMAND_0100 INPUT

Agregamos WHEN ‘PROCESAR’ lo cual significa que vamos a
ejecutar una acción cuando se presione el botón. La acción que
vamos a ejecutar es el FORM PROCESAR_DATOS.

FORM PROCESAR_DATOS.

DATA: LINEAS TYPE I,
ID TYPE ZPROGRAMAS-ID.

ID = ZPROGRAMAS-ID.

IF ID NE SPACE.
SELECT *
INTO TABLE T_ZPROGRAMAS
FROM ZPROGRAMAS

238

WHERE ID EQ ID.

DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS.

TABLA-LINES = LINEAS.
ENDIF.

ENDFORM. " PROCESAR_DATOS

Se darán cuenta de que el código es el mismo que estaba dentro del
MODULE STATUS_0100 OUTPUT. Con lo cual el módulo
quedaría así.

MODULE STATUS_0100 OUTPUT.

SET PF-STATUS '100'.
SET TITLEBAR '100'.

ENDMODULE. " STATUS_0100 OUTPUT

Si ejecutamos el programa (Ahora tenemos que presionar el botón
para que se llene la tabla).

239

Si han sido curiosos u observadores, se habrán dado cuenta de que
los campos de la tabla pueden modificarse, por lo tanto podríamos
cambiar los valores que obtenemos de la tabla.
Corregir esto es muy sencillo, simplemente regresamos a la
transacción SE51 y vamos a las propiedades de los campos que
conforman la tabla.
Por defecto tenemos esto.

Por lo tanto, debemos desmarcar el campo Input Field (Campo de
entrada), para que los valores de la tabla no puedan ser modificados.
Si ejecutamos de nuevo el programa, veremos que los campos están
protegidos de malas acciones.

240

Programación Avanzada en Dynpros

Ahora que ya hemos trabajado un poco con Dynpros, y conocemos
su funcionamiento, es hora de que hagamos cosas un poco más
interesantes.

1.- MatchCodes dinámicos

¿Qué es un MatchCode? Pues simplemente es, la pequeña ventana
con valores que aparecen luego de que hacemos clic en un campo o
presionamos F4.
Los MatchCodes dinámicos, se pueden crear de dos maneras. A
partir de una ayuda de búsqueda (En este caso, el MatchCode nos
ayuda a realizar una delimitación automática de valores) o utilizando
una tabla interna.
Como nuestro parámetro FILTRO ya posee un MatchCode, vamos
a asignarle uno nuevo.
En el Flow Logic debemos agregar el siguiente código.

PROCESS ON VALUE-REQUEST.
FIELD ZPROGRAMAS-ID MODULE MATCH_CODE_ID.

Lo que hace el POV (Process on value-request / Proceso en
requerimiento de valor) es llamar a un módulo cuando presionamos
F4 en un campo. Gracias a esto, podemos definir nosotros mismos la
ayuda de búsqueda.

241

Lo primero que debemos hacer es crear el módulo, que como ya
sabemos se hace haciendo doble clic sobre el nombre del módulo.
De vuelta en nuestro programa, debemos crear un TYPE que defina
nuestro MatchCode.

*=====================================================*
* DECLARACION DE TYPES *
*=====================================================*
TYPES: BEGIN OF TY_MATCHCODE_ID,
ID TYPE ZPROGRAMAS-ID,
END OF TY_MATCHCODE_ID.

Un TYPE no es más que un modo genérico de crear una tabla
interna, algo así como una plantilla.
Luego, debemos crear una tabla interna que haga referencia al tipo
que hemos creado.

*=====================================================*
* DECLARACION DE TABLAS INTERNAS *
*=====================================================*
DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF
ZPROGRAMAS WITH HEADER LINE,
T_MATCHCODE_ID TYPE STANDARD TABLE OF
TY_MATCHCODE_ID WITH HEADER LINE.

Es importante que lo creemos con cabecera (Aunque esto sea romper
las reglas…
Además, debemos crear algunas variables necesarias para la función
que genera los MatchCodes.

242

*=====================================================*
* DECLARACION DE VARIABLES *
*=====================================================*
DATA: DYNPROFIELD TYPE HELP_INFO-DYNPROFLD,
PROGNAME TYPE SY-REPID,
DYNNUM TYPE SY-DYNNR.

Adicionalmente, necesitamos una tabla interna para la función que
crea los MatchCodes dinámicos.

RETURN_TAB TYPE STANDARD TABLE OF DDSHRETVAL
WITH HEADER LINE.

Con esto, ya estamos listos para programar nuestro
MatchCode…Claro ustedes se preguntarán...¿Qué vamos a
hacer...Si el campo ID ya tiene un MatchCode? Muy
simple...Nuestro MatchCode va a mostrar solamente el ID y ya no
el ID y el Nombre...Claro debería de ser al revés, pero el ejemplo
sirve para ilustrar lo que podemos hacer.
Antes de continuar, como vamos a llamar a un Módulo de
Funciones, podemos utilizar un poco de ayuda.

Presionamos el botón Pattern (Patrón) y veremos una
pantalla muy interesante.
Esta pantalla completa el código por nosotros utilizando una
plantilla, en donde los parámetros no obligatorios están comentados.
Ingresamos F4IF_INT_TABLE_VALUE_REQUEST en el campo
CALL FUNCION (Llamar función) y aceptamos.

243

SELECT ID INTO TABLE T_MATCHCODE_ID FROM ZPROGRAMAS. REFRESH RETURN_TAB. PROGNAME = SY-REPID. DYNPROFIELD = 'ZPROGRAMAS-ID'. DYNNUM = '100'. CLEAR RETURN_TAB.MODULE MATCH_CODE_ID INPUT. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD = 'ID' DYNPPROG = PROGNAME 244 .

IF RETURN_TAB-FIELDVAL NE SPACE. ENDIF. PROGNAME = SY-REPID. DYNPROFIELD = 'ZPROGRAMAS-ID'. DYNPNR = DYNNUM DYNPROFIELD = DYNPROFIELD VALUE_ORG = 'S' TABLES VALUE_TAB = T_MATCHCODE_ID RETURN_TAB = RETURN_TAB EXCEPTIONS PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3. ZPROGRAMAS-ID = RETURN_TAB-FIELDVAL. SELECT ID INTO TABLE T_MATCHCODE_ID FROM ZPROGRAMAS. ENDMODULE. Seleccionamos todos los ID’s de la tabla ZPROGRAMAS. 245 .. " MATCH_CODE_ID INPUT Revisemos un poco el código.. DYNNUM = '100'.

CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD = 'ID' DYNPPROG = PROGNAME DYNPNR = DYNNUM DYNPROFIELD = DYNPROFIELD VALUE_ORG = 'S' TABLES VALUE_TAB = T_MATCHCODE_ID RETURN_TAB = RETURN_TAB EXCEPTIONS PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3. ZPROGRAMAS-ID = RETURN_TAB-FIELDVAL. 246 .El campo DYNPROFIELD almacena a que campo se va a aplicar el MatchCode. ENDIF. CLEAR RETURN_TAB. IF RETURN_TAB-FIELDVAL NE SPACE. el campo DYNNUM almacena cual es el número del Dynpro y el campo PROGNAME almanacena cual es el nombre del programa. Limpiamos la cabecera y el contenido de la tabla RETURN_TAB. REFRESH RETURN_TAB.

2. Nos muestra una ventana con los valores disponibles y el que hayamos elegido es guardado en la tabla RETURN_TAB.El módulo de funciones recibe las variables con la información del Dynpro y la tabla conteniendo los valores de los ID’s.Eliminar registros en un table control Ahora. y supone hacer unas cuantas modificaciones en los atributos de la tabla. supongamos que queremos tener la posibilidad de elegir un registro y eliminarlo. Si hemos escogido algún valor. Listo. 247 .. tenemos un MatchCode dinámico. (Además de agregar algunos registros más en nuestra tabla ZPROGRAMAS). entonces lo mostramos en el campo ZPROGRAMAS-ID. Esto es bastante sencillo.

Debemos marcar el check w/SelColumn (con Selección de columna) y asignarle un nombre. va a ser “FILA”. Además. 248 . vamos a agregar un botón llamado ELIMINAR. que en este caso. La variable FILA nos a indicar cuando hayamos seleccionado un registro.

el botón tiene un FctCode llamado “ELIMINA” y un Icono llamado ICON_DELETE. 249 .Como vemos. además de un Tooltip con el texto “Eliminar”.

en ese momento el 250 . PROCESS AFTER INPUT. entonces continuamos. DELETE T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. recordemos que esta variable va a ser equivalente a la del Dynpro. Creamos el módulo dentro de nuestro programa. MODULE USER_COMMAND_0100. Si hemos presionado el botón ELIMINAR. LOOP AT T_ZPROGRAMAS. MODULE ELIMINAR_FILA.Tenemos que ingresar al Flow Logic para crear un módulo asociado el botón ELIMINAR. " ELIMINAR_FILA INPUT Declaramos una variable llamada FILA de tipo C. DATA: FILA TYPE C. ENDMODULE. IF SY-UCOMM EQ 'ELIMINA'. ENDIF. MODULE ELIMINAR_FILA INPUT. y automáticamente. el sistema va a recorrer todas las filas de nuestra tabla hasta encontrar la que esté seleccionada. IF FILA EQ 'X'. ENDIF. ENDLOOP.

3. aunque sería bastante sencillo hacer que lo haga.valor de FILA va a ser ‘X’. LOOP AT T_ZPROGRAMAS. PROCESS AFTER INPUT. necesitemos modificar algún registro de nuestro table control.. 251 . Recuerden que quitamos este valor para otro de los ejemplos. se borra también de la tabla. MODULE ELIMINAR_FILA. deberíamos poder tener la posibilidad de Escritura y Lectura. Borramos este valor de nuestra tabla interna y como consecuencia. por lo tanto. debemos crear un nuevo módulo en nuestro Screen Painter. Debemos modificar los atributos de la tabla para que sea de Escritura/Lectura. Ahora. MODULE USER_COMMAND_0100. Claro. simplemente necesitaríamos seleccionar la llave primaria de la tabla y hacer un DELETE TABLE.Escritura/Lectura en un table control Puede ser que en algún momento. esto no lo borra de la Base de Datos.

Dentro del programa. ENDMODULE. 252 . MODIFY T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. " ACTUALIZA_TABLA INPUT Con esto. La variable CURRENT_LINE nos indica que registro es el que estamos modificando. lo que vamos a hacer es agregar un botón que nos permita cambiar entre el modo visualización y el modo modificación en el programa. ENDLOOP. modificaremos el contenido del registro del table control que hemos modificado. MODULE ACTUALIZA_TABLA. deberemos colocar el siguiente código al módulo. Ahora. MODULE ACTUALIZA_TABLA INPUT.

253 . En este caso. vamos a agregar un pulsador en el menú (Menú Painter – SE41). podemos definir un Static Text (Texto Estático) o un Dynamic Text (Texto Dinámico).Para esto. Empecemos creando uno estático. En la primera casilla escribimos CHANGESTAT y presionamos ENTER.

el texto asociado a la función. 254 .En esta ventana. definimos el código de función asociado al pulsador. el icono asociado y finalmente el texto informativo.

queda así. 255 . deberemos hacer un clic al costado del Icono para una última ventana de propiedades. Cuando grabamos y activamos. En el caso de nos especificar ningún texto. Finalmente. En este caso. debemos escoger el texto que acompañará al icono que hemos seleccionado. el sistema tomará el texto por defecto del pulsador. vamos a elegir el F2. En esta nueva ventana.Debemos asignar una tecla de función a cada pulsador que creemos.

Finalmente tendremos esto. En este caso. TEXTO_DINAMICO TYPE SMP_DYNTXT.Le toca ahora al pulsador con texto dinámico. Asignaremos cualquier tecla de función y continuaremos. debemos escoger Dynamic Text esta vez). DYNNUM TYPE SY-DYNNR. tendremos que crear una variable y asignarle valores para nuestro texto dinámico. Debemos seguir los pasos anteriores hasta que lleguemos a esta pantalla (Claro. Field name (Nombre Campo) es una variable que deberemos crear en nuestro programa. PROGNAME TYPE SY-REPID. DATA: DYNPROFIELD TYPE HELP_INFO-DYNPROFLD. 256 . De vuelta en el programa. veamos como crearlo.

esto es porque TABLA-COLS es una Deep Structure 257 . Nuevamente deben de estar como campos de salida. Creamos una tabla de tipo COLS que pertenece a TABLA y contiene los atributos de todos los registros que componen la TABLA. TEXTO_DINAMICO = 'Este es un texto dinámico'. En el Screen Painter debemos cambiar los atributos de los componentes de la tabla. deberemos hacer lo siguiente. CALL SCREEN '100'. En el programa. START-OF-SELECTION. START-OF-SELECTION. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. DATA: COLS LIKE LINE OF TABLA-COLS. TEXTO_DINAMICO = 'Este es un texto dinámico'. CALL SCREEN '100'.Y debemos también asignarle un texto inicial. Esto es para que los componentes de la tabla estén protegidos por defecto. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. Declaramos la tabla COLS como una línea de la tabla TABLA- COLS.

PERFORM CAMBIAR_ESTADO. CASE OK_CODE. WHEN 'PROCESAR'. FORM CAMBIAR_ESTADO. ENDCASE. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. OK_CODE = SY-UCOMM. IF COLS-SCREEN-INPUT = '0'. ENDMODULE. ELSEIF COLS-SCREEN-INPUT = '1'. creamos el FORM CAMBIAR_ESTADO. Agregamos el evento generado por el pulsador CHANGESTAT. es una tabla dentro de otra tabla. TEXTO_DINAMICO = 'Modificar'.(Estructura profunda). PERFORM PROCESAR_DATOS. WHEN 'CHANGESTAT'. DATA: OK_CODE TYPE SY-UCOMM. LOOP AT TABLA-COLS INTO COLS. Además. SET SCREEN 0. LEAVE SCREEN. MODULE USER_COMMAND_0100 INPUT. " USER_COMMAND_0100 INPUT Para terminar. solo necesitamos una cabecera y no toda la tabla. COLS-SCREEN-INPUT = '1'. es decir. 258 . CLEAR SY-UCOMM.

ENDLOOP. 259 . si es cero. Verificamos el estado del campo INPUT. COLS-SCREEN-INPUT = '0'. Cambiamos los estados. ENDFORM. ENDIF. MODIFY TABLA-COLS FROM COLS. TEXTO_DINAMICO = 'Visualizar'. entonces estamos visualizando y si es uno estamos modificando. " CAMBIAR_ESTADO Hacemos un LOOP a la tabla TABLA-COLS y guardamos cada línea o registro dentro de nuestra tabla COLS. los textos del botón dinámico y finalmente modificamos la tabla para que los cambios queden registrados.

Trabajando con SubScreens 260 .

Y por supuesto nuestro TabStrip Control llamado “TAB”. 261 . los TABS no van a funcionar. y vamos a crear uno nuevo utilizando pestañas y un SubScreen. Vamos a crear una nueva pantalla y un nuevo programa. Vamos a olvidarnos de nuestro programa anterior.Algunas veces necesitamos incluir pantallas completas de otras pantallas. Asignamos un nombre a cada TAB (Pestaña) del TabStrip Control. puesto que sin esto. sobre todo cuando tenemos que utilizar Tabs o Pestañas. Es muy importante que definamos el Tipo de Función que este caso es P (Local Gui Function – Función GUI Local).

puesto que son contenedores que admiten únicamente pantalla de tipo SubScreen. la 101 y 102. pero esta vez de tipo SubScreen. Así que debemos crear dos pantallas más. Dentro de los SubScreens no podemos colocar ningún control. y lo asignamos al control TAB. 262 . La única propiedad que tenemos que definir para el SubScreen es el nombre.Creamos un SubScreen.

este será el Flow Logic para la pantalla principal.Luego de haber creado las dos SubScreens. MODULE USER_COMMAND_0100. CALL SUBSCREEN: SUBSCREEN_2 INCLUDING SY-REPID '0102'. Con el INCLUDING referenciamos al programa control y al número de la pantalla. PROCESS AFTER INPUT. PROCESS BEFORE OUTPUT. CALL SUBSCREEN: SUBSCREEN_1 INCLUDING SY-REPID '0101'.SUBSCREEN_2. CALL SUBSCREEN: SUBSCREEN_1. 263 . MODULE STATUS_0100. Con el CALL SUBSCREEN llamamos a cada una de las pantallas SubScreen que creamos.

• ZLENGUAJES_PROG-NOMBRE. Como mencioné lineas arriba. el nombre será ZPROGRAMAS-ID. En este caso. tendremos que utilizar el nombre TABLA- CAMPO como nombre. los componentes tendremos que colocarlos dentro de cada SubScreen. en el PAI también utilizamos el CALL SUBSCREEN para llamar a las SubScreens. Si queremos que esté asociado con una tabla de la Base de Datos. por lo cual vamos a comenzar con el número 0101. vamos a tener dos campos de Entrada/Salida. Vamos a crear un Box o Caja con los siguientes atributos. Dentro del Box (Caja). Además.Como podemos ver. vamos a crear un campo de texto para el código del programa. 264 . Vamos a agregar también un botón llamado PROCESAR y que va a tener como código de función la palabra PROCESS. • ZPROGRAMAS-NOM_PROG.

puesto que una vez obtenidos los datos del programa. los nombres de los componentes no pueden repetirse. Pero aquí simplemente vamos a utilizar variables para el segundo SubScreen.Lo mejor sería crear una estructura para cada una de ellas y problema resuelto. En el cual no podrán ser modificados.. Cabe destacar que aunque tengamos pensado utilizar dos SubScreens. podremos modificarlos y mostrarlos en el segundo SubScreen. es decir.. no podemos crear el campo ZPROGRAMAS- NOM_PROG en ambas pantallas. 265 .Finalmente. tendremos un botón llamado MODIFICAR con el código de función MODIFY. Este botón nos va a servir.

indica que pestaña del TAB va a estar activa cuando ejecutemos el programa. SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE. TAB_CONTROL-ACTIVETAB = 'TAB_1'. "OBTENER_DATOS 266 .Por lo tanto. vamos a tener V_NOM_PROG y V_NOMBRE. crear las variables correspondientes y crear el componente TAB_CONTROL. CALL SCREEN '100'. La sentencia TAB_CONTROL-ACTIVETAB.ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID. CONTROLS TAB_CONTROL TYPE TABSTRIP. En el programa. ENDFORM. deberemos declarar la tablas ZPROGRAMAS y ZLENGUAJES_PROG. Para el botón PROCESAR vamos a crear el siguiente form. START-OF-SELECTION. FORM OBTENER_DATOS.

No debemos olvidarnos del USER-COMMAND. OK_CODE = SY-UCOMM. " USER_COMMAND_0100 INPUT 267 . PERFORM OBTENER_DATOS. CLEAR SY-UCOMM. MODULE USER_COMMAND_0100 INPUT. DATA: OK_CODE TYPE SY-UCOMM. y obtenemos los valores NOMBRE y NOM_PROG. ENDCASE. ENDMODULE. los cuales son guardados en los Campos de Entrada/Salida del Dynpro. WHEN 'PROCESS'. CASE OK_CODE.Hacemos un INNER JOIN entre las dos tablas.

STEPL TYPE DYNPREAD-STEPL. y como debe ser. los datos se quedan pegados. Por suerte. FIELDVALUE TYPE DYNPREAD-FIELDVALUE. debemos crear los siguientes TYPES y Tablas Internas. 268 . Esto es porque estamos trabajando en un SubScreen y los datos no se actualizan directamente.Cuando ingresamos el primer código. nos vamos a dar cuenta de algo bastante peculiar... *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TAB. existe una función que actualiza los Dynpros. Para esto. todo va bien. pero con el segundo. FIELDNAME TYPE DYNPREAD-FIELDNAME.Cuando ejecutamos el programa.

FIELDINP TYPE DYNPREAD-FIELDINP. END OF TAB. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: MY_TAB TYPE STANDARD TABLE OF TAB. FIELD-SYMBOLS: <FS_MY_DYNP> LIKE LINE OF MY_DYNP. <FS_MY_TAB> LIKE LINE OF MY_TAB. TYPES: BEGIN OF DYNP. FORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP. DYNUMB TYPE D020S-DNUM. END OF DYNP. CALL FUNCTION 'DYNP_UPDATE_FIELDS' EXPORTING DYNAME = SY-CPROG DYNUMB = <FS_MY_DYNP>-DYNUMB REQUEST = 'A' TABLES 269 . MY_DYNP TYPE STANDARD TABLE OF DYNP. LOOP AT MY_DYNP ASSIGNING <FS_MY_DYNP>. Nuestro FORM para actualizar el Dynpro será el siguiente (Aunque primero debemos crear dos Field-Symbols.

APPEND INITIAL LINE TO MY_TAB 270 . APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>.ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID. REFRESH: MY_TAB. FORM OBTENER_DATOS. "ACTUALIZAR_DYNPRO El módulo de funciones DYNP_UPDATE_FIELD lo que hace es actualizar cada campo recibido en MY_TAB de acuerdo a la pantalla especificada en <FS_MY_DYNP>-DYNUMB. IF SY-SUBRC EQ 0. MY_DYNP. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-ID. SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE. APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>. podemos mejorar la rutina OBTENER_DATOS. ENDFORM. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-NOM_PROG. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-NOM_PROG'. DYNPFIELDS = MY_TAB. Gracias a esto. ENDLOOP. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-ID'.

Finalmente llamamos al FORM ACTUALIZAR_DYNPRO pasando las tablas como parámetros. OK_CODE = SY-UCOMM. <FS_MY_DYNP>-DYNUMB = '0101'. CLEAR SY-UCOMM. PERFORM OBTENER_DATOS. CASE OK_CODE. <FS_MY_TAB>-FIELDNAME = 'ZLENGUAJES_PROG-NOMBRE'. DATA: OK_CODE TYPE SY-UCOMM. "OBTENER_DATOS Primero. si el SELECT es exitoso. WHEN 'PROCESS'. agregamos los campos del Dynpro a nuestra tabla MY_TAB. APPEND INITIAL LINE TO MY_DYNP ASSIGNING <FS_MY_DYNP>. MODULE USER_COMMAND_0100 INPUT. ENDFORM. ENDIF. ASSIGNING <FS_MY_TAB>. Con esto listo. podemos continuar con el botón MODIFICAR. 271 . además agregamos el número del Dynpro a nuestra tabla MY_DYNP. <FS_MY_TAB>-FIELDVALUE = ZLENGUAJES_PROG-NOMBRE. PERFORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP.

" TRASPASAR_VALORES 272 . ENDFORM. (Aunque antes creamos un par de variables que están relacionadas con los campos del segundo SubScreen). ENDMODULE. CLEAR: V_NOM_PROG. PERFORM TRASPASAR_VALORES. V_NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. WHEN 'MODIFY'. ENDCASE. DATA: V_NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. MOVE ZLENGUAJES_PROG-NOMBRE TO V_NOMBRE. MOVE ZPROGRAMAS-NOM_PROG TO V_NOM_PROG.V_NOMBRE. " USER_COMMAND_0100 INPUT Creamos el nuevo FORM. FORM TRASPASAR_VALORES.

273 .

En el Flow Logic. Debemos crear un campo de Entrada/Salido asociado al campo ZPROGRAMAS-ID. pero debemos asignarle un atributo especial.Utilizando Listas Deplegables Lo que vamos a hacer ahora. que es el de Listbox (Lista desplegable). es obtener los datos de la tabla ZPROGRAMAS. utilizando un lista desplegable que nos muestre todos los códigos de programas. pero esta vez. 274 . crearemos un módulo que llene la lista con datos.

Como era de esperarse. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPE-POOLS: VRM. MODULE USER_COMMAND_0100. tablas internas. un Type e inclusive un Type-Pool. Como ven. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: ID TYPE VRM_ID. MODULE STATUS_0100. MODULE LLENAR_LISTA_DESPLEGABLE. 275 . debemos crear algunas variables.PROCESS BEFORE OUTPUT. FC_VALUES LIKE VALUES WITH HEADER LINE.Esto es porque el componente Listbox sigue siendo parte del ABAP antiguo. PROCESS AFTER INPUT. nuevamente necesitamos una tabla con cabecera.. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: VALUES TYPE VRM_VALUES..

SELECT ID NOMBRE INTO (FC_VALUES-KEY. ya se que se ve un poco redundante. ENDSELECT. CALL FUNCTION 'VRM_SET_VALUES' EXPORTING ID = ID VALUES = VALUES EXCEPTIONS ID_ILLEGAL_NAME = 1 OTHERS = 2. ENDLOOP. LOOP AT FC_VALUES. MODULE LLENAR_LISTA_DESPLEGABLE OUTPUT. ID = 'ZPROGRAMAS-ID'. " LLENAR_LISTA_DESPLEGABLE OUTPUT 276 .Este es el código que utilizaremos para llenar con datos la lista. APPEND FC_VALUES TO VALUES. pero la estructura de la función que genera la lista así lo requiere. ENDMODULE.FC_VALUES-TEXT) FROM ZLENGUAJES_PROG. IF ID EQ SPACE. APPEND FC_VALUES. ENDIF.

nos muestra el nombre del lenguaje en un espacio muy reducido. se muestren los datos. antes de poder continuar. en este caso necesitamos el SELECT-ENDSELECT (El GOTO del ABAP). Para esto. Necesitamos que los valores queden almacenados en la tabla VALUES que es la que vamos a pasar al módulo de funciones VRM_SET_VALUES. que es el que finalmente crea la lista despegable. además. pero no hace nada. veremos que la lista está llena. puesto que si seleccionamos un lenguaje de programación.Aunque no es nada recomendable utilizarlo. sin necesidad de un botón auxiliar. simplemente agregamos un código de función al componente. así que deberíamos ampliar un poco su tamaño. no nos muestra los datos. Si ejecutamos el programa. 277 . Así que vamos a hacer que cuando seleccionemos el lenguaje.

Dentro del programa. WHEN 'LISTA'. MODULE USER_COMMAND_0100 INPUT. ENDFORM. CLEAR SY-UCOMM. agregamos una llamada al código de función. OK_CODE = SY-UCOMM. CLEAR: ZPROGRAMAS-ID_PROG. " OBTENER_DATOS 278 .ZPROGRAMAS-NOM_PROG) FROM ZPROGRAMAS WHERE ID EQ ZPROGRAMAS-ID. podemos llamar al FORM OBTENER_DATOS. IF SY-SUBRC NE 0. DATA: OK_CODE TYPE SY-UCOMM. FORM OBTENER_DATOS. ENDIF. ENDMODULE. " USER_COMMAND_0100 INPUT Con esto listo. SELECT SINGLE ID_PROG NOM_PROG INTO (ZPROGRAMAS-ID_PROG.ZPROGRAMAS-NOM_PROG. CASE OK_CODE. PERFORM OBTENER_DATOS. ENDCASE.

Ahora. cuando elegimos un valor de la lista desplegable. 279 . podemos obtener los datos asociados.

280 . FREE DYNPRO_VALUES. DATA: DYNPRO_VALUES TYPE TABLE OF DYNPREAD WITH HEADER LINE. FIELD_VALUE-FIELDNAME = 'ZPROGRAMAS-ID'. DATA: DYNUM TYPE D020S-DNUM. FIELD_VALUE LIKE LINE OF DYNPRO_VALUES. MODULE USER_COMMAND_0100. existe una función muy útil para leer los valores de un Dynpro. por eso. APPEND FIELD_VALUE TO DYNPRO_VALUES. FREE FIELD_VALUE. Y creamos un módulo para leer los valores del Dynpro. MODULE READ_DYNP_VALUES INPUT. pero nos damos cuenta de que este no está activo hasta que presionamos la tecla ENTER o activamos algún evento.Leyendo datos de un Dynpro Algunas veces. Obviamente no podemos obligar al usuario a presionar ENTER o activar un evento. MODULE READ_DYNP_VALUES. necesitamos leer el valor de un componente del Dynpro. Necesitaremos crear dos tablas internas y una variable. PROCESS AFTER INPUT.

DYNUMB = '0100'. entonces lo asignamos a nuestro campo o a donde lo necesitemos. 281 . READ TABLE DYNPRO_VALUES WITH KEY FIELDNAME = 'ZPROGRAMAS-ID'. ENDMODULE. ZPROGRAMAS-ID = DYNPRO_VALUES-FIELDVALUE. ENDIF. y el valor que queremos leer. tenemos que pasar el número del Dynpro. IF SY-SUBRC EQ 0. " READ_DYNP_VALUES INPUT Como podemos ver. Si la función puede leerlo. CALL FUNCTION 'DYNP_VALUES_READ' EXPORTING DYNAME = SY-CPROG DYNUMB = DYNUMB TABLES DYNPFIELDS = DYNPRO_VALUES.

crearemos nuestra ZDUMMY_FUNCTION. los Standard y los RFC (Remote Function Call – Llamada de Procedimiento Remoto). definamos que va a hacer nuestra función. En la transacción SE37. es un programa capaz de recibir parámetros de entrada y producir un resultado. Por ejemplo. Los módulos de función son creados en la transacción SE37. meses. Para empezar. así que vamos a crear uno bastante sencillo. fuera del programa que lo utiliza. Se diferencia de una función normal. Para 282 . utilizaremos el grupo de funciones que creamos en la sección Creando una vista de Actualización. Para esto. en que puede poseer una estructura bastante compleja y debe ser diseñado en su propio entorno. calcular la edad de una persona en años. la mejor explicación es un ejemplo. Creando nuestra primera función Como siempre. que sirven para la comunicación entre sistemas externos y el NetWeaver. días.Módulos de Función y BAPIS Introducción Módulos de Función Un módulo de funciones. Existen dos tipos de módulos de funciones.

necesitaremos como parámetro de entrada la fecha de nacimiento del usuario y como salida podemos mostrar una tabla que contenga los campos años. necesitaremos crear una estructura que contenga dichos campos. meses y días. solo vamos a utilizar un parámetro de entrada. llamado FECHA_NAC de tipo SY-DATUM. Vamos a llamarla ZEDAD_STR. Cuando creemos la función.esto. hay ciertos campos que debemos ir llenando. 283 . Por lo tanto. En este caso.

En la pestaña Changing (Cambiando). Para todos los parámetros existen un botón muy importante llamado Long text (Texto largo) . grabamos. nos permite crear un texto de ayuda que indica que hace o que necesita el parámetro para funcionar correctamente. Basta con hacer clic en el botón Create (Crear) para ingresar al editor. Este botón. Optional (Opcional). En este caso. hay dos CheckBox. que indica si el campo es obligatorio o no y Pass Value (Pasar valor) que indica si el valor es pasado por Valor o por Referencia. es decir. 284 . que hará referencia a la estructura que hemos creado.Como podemos ver. activamos y salimos. Escribimos un pequeño texto descriptivo. vamos a crear nuestro parámetro de salida. mantenemos los valores por defecto. dejamos ambos como están.

. podemos pasar a la pestaña de Source Code (Código Fuente) en donde vamos a crear el código necesario para que nuestra función.funcione. pero a modo de ejemplo nos va a ser útil. deberíamos mostrar un mensaje de error. Finalmente.Luego de esto. indicándonos que el texto ha sido asignado correctamente. *"----------------------------------------------------- *"*"Local Interface: *" IMPORTING *" REFERENCE(FECHA_NAC) TYPE SY-DATUM *" CHANGING 285 . que son errores que puede encontrar la función. si la fecha de nacimiento ingresada como parámetro es mayor que la fecha actual. Claro. Esto lo hacemos ingresando a la pestaña Exceptions (Excepciones). podemos darnos cuenta de que el botón ha cambiado. no va a ser el cálculo más exacto.. es importante saber que podemos asignar excepciones. Antes de comenzar con el código. por ejemplo. FUNCTION ZDUMMY_FUNCTION.

TABLA_EDAD-ZDAYS = ZDAYS. RAISE EDAD_FUERA_RANGO.*" REFERENCE(TABLA_EDAD) TYPE ZEDAD_STR *" EXCEPTIONS *" EDAD_FUERA_RANGO *"----------------------------------------------------- DATA: ZYEARS(4) TYPE C. ZMONTHS = ZMONTHS . IF SY-DATUM+4(2) LT ZMONTHS. ZYEARS = ZYEARS . ZYEARS = SY-DATUM+0(4) . 286 . ENDIF. ZDAYS = ZDAYS + SY-DATUM+6(2). ZDAYS(2) TYPE C.1. ZDAYS = FECHA_NAC+6(2). IF SY-DATUM+6(2) LT ZDAYS. ZDAYS = 30 . ENDIF. ENDIF. ZMONTHS = SY-DATUM+4(2) + 1. ZYEARS = FECHA_NAC+0(4). IF FECHA_NAC GT SY-DATUM. TABLA_EDAD-ZYEARS = ZYEARS. ZMONTHS(2) TYPE C.ZDAYS. ZMONTHS = FECHA_NAC+4(2).1.ZYEARS. TABLA_EDAD-ZMONTHS = ZMONTHS.

IF FECHA_NAC GT SY-DATUM. lanzamos un mensaje de error. otra el mes y la última los días. para poder obtener los años. Además una variable auxiliar para los meses. Si la fecha de nacimiento ingresada. ZMONTHS(2) TYPE C. DATA: ZYEARS(4) TYPE C. utilizamos posiciones de inicio y cantidad de caracteres. ZDAYS(2) TYPE C. RAISE EDAD_FUERA_RANGO.1977 se almacena como 19771122. una para guardar el año. ZMONTHS = FECHA_NAC+4(2). meses y días en variables. Declaramos 3 variables. Revisemos un poco el código. las fechas se almacenan en un orden inverso.11. ZDAYS = FECHA_NAC+6(2). al ingresar nosotros 22.ZYEARS. por lo tanto. En SAP. ZYEARS = SY-DATUM+0(4) . ZYEARS = FECHA_NAC+0(4). al 287 . Entonces. ZMONTHS_AUX TYPE C. es decir.ENDFUNCTION. ENDIF. es menor a la fecha actual del sistema.

entonces debemos restar un año. Restamos el año actual. Restamos 1 a meses y sumamos los días actuales más los días que obtuvimos al hacer la resta de 30 menos los días del parámetro. Si los días actuales son menores que los días del parámetro. finalmente. comenzando desde el carácter 0”.ZDAYS. ZMONTHS = ZMONTHS . ZYEARS = ZYEARS . ENDIF. “Toma 4 caracteres. Para probar nuestra función. IF SY-DATUM+6(2) LT ZDAYS. ZMONTHS = SY-DATUM+4(2) + ZMONTHS.1. ZDAYS = ZDAYS + SY-DATUM+6(2). entonces a 30 le restamos la cantidad de días.1. Restamos la cantidad de meses a 12. para saber cuantos hay de diferencia. ZMONTHS_AUX = 12 .tener nostros FECHA_NAC+0(4) estamos diciendo. menos el año del parámetro. sumamos esos meses de diferencia. IF SY-DATUM+4(2) LT ZMONTHS. simplemente debemos ejecutarla presionando la tecla F8 o el botón Test/Exectute (Probar/Ejecutar) . ZDAYS = 30 . 288 . En otras palabras 1977. Si el mes actual es menor que el mes del parámetro.ZMONTHS. ENDIF.

debemos hacer clic en Details View/Edit (Visualizar/Editar Detalles) . ya sea con el botón Execute (Ejecutar) o presionando F8 . Además podríamos hacer un debug si presionaramos el botón Debugging o las teclas Ctrl + F7 . Para ver más claramente el resultado. 289 .Ingresamos una fecha de nacimiento y lo ejecutamos.

01 mes y 09 días. es hora de llamarla desde un programa. Ahora que ya vimos que nuestra función hace lo que tiene que hacer. deberemos presionar el botón Single Entry (Entrada Individual) o presionar los botones Shift + F7 . Si queremos ver el resultado con un mayor detalle. la manera más sencilla de llamar a una función es con el botón Pattern (Patrón) tal y como vimos en una sección anterior.30 Años. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. Llamando funciones desde un programa Dentro de nuestro programa. 290 .

*=====================================================* * DECLARACION DE TABLAS * *=====================================================* DATA: TABLA_EDAD TYPE ZEDAD_STR. 291 . IF SY-SUBRC <> 0. PARAMETERS: P_FECHA TYPE SY-DATUM. SELECTION-SCREEN END OF BLOCK DATA. ELSE. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. WRITE: 'La edad ingresada está fuera del rango'. CALL FUNCTION 'ZDUMMY_FUNCTION' EXPORTING FECHA_NAC = P_FECHA CHANGING TABLA_EDAD = TABLA_EDAD EXCEPTIONS EDAD_FUERA_RANGO = 1 OTHERS = 2. 'Años'. WRITE: 'Su edad actual es'. TABLA_EDAD-ZYEARS. *=====================================================* * Selection screen * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME.

ENDIF. 'Meses'. etc. obtenemos los datos y los mostramos en pantalla. El código es bastante sencillo y no necesita mayor explicación. TABLA_EDAD-ZDAYS. 'Días'. crear pedidos. TABLA_EDAD-ZMONTHS. no es en el fondo más que un módulo de funciones con características de RFC. Introducción BAPIS Una BAPI (Business Application Programming Interface – Interface de Programación de Aplicaciones de Negocio). como por ejemplo. Aunque las BAPI’s son utilizadas para realizar tareas específicas. Llamamos a la función. realizar contabilizaciones. cargar datos maestros. 292 .

Además. 293 . puesto que cuentan con muchos mecanismos de control y aseguramiento.Las BAPI’s son estables. Por eso. encapsulan operaciones complejas en una simple interfaz. las BAPI’s cuentan con su propia transacción llamada justamente BAPI.

puesto que una vez que tengamos lista la tabla interna. 294 . por lo general son bastante sencillos y estáticos puesto que simplemente muestran información. es obtener los datos tal como lo haríamos en un programa normal. y nos permiten ocultar o visualizar columnas. llamado SLIS.ALV (ABAP List Viewer) Introducción En ABAP es muy común crear reportes que muestren información de varias tablas. Estos reportes. Creando un ALV Para crear un ALV. necesitamos una función muy importante llamada REUSE_ALV_GRID_DISPLAY. Lo primero que hay que hacer. promedios y muchas cosas más. nos ofrece los ALV’s que son Visores de Listas ABAP. así que veamos como sería el esqueleto del programa. contiene todas las definiciones de variables y tablas internas que necesitamos para poder trabajar. que es la que finalmente crea todo el diseño visual y la gran mayoría de las funcionalidades standard que nos ofrecen estos reportes dinámicos. Otro punto importante. ABAP. ordenar datos. Estas listas son interactivas. Este TYPE-POOLS. es el uso de un TYPE-POOLS. será muy sencillo generar el ALV. mostrar subtotales.

NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. END OF TY_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. *=====================================================* * Selection screen * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. SELECT-OPTIONS: 295 . *=====================================================* * DECLARACION DE TYPE-POOLS * *=====================================================* TYPE-POOLS: SLIS.*=====================================================* * DECLARACION DE TABLAS * *=====================================================* TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS.

" OBTENER_DATOS Vamos a necesitar crear algunas tablas internas para poder llenar las estructuras del ALV. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. SELECTION-SCREEN END OF BLOCK DATA. 296 . I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. PERFORM OBTENER_DATOS. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. S_IDPROG FOR ZPROGRAMAS-ID_PROG. *&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. así como algunas variables para manejar su formato de visualización. ENDFORM. SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP INTO TABLE T_PROGRAMAS FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ID_PROG IN S_IDPROG.

En este evento. I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. G_TITULO TYPE SY-TITLE. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: G_PROGRAM TYPE SY-REPID. que se dispara cuando se ha terminado la selección de datos. Vamos a agregar un nuevo evento. vamos a agregar una serie de funciones que se van a encargar de formar el ALV. PERFORM F_GENERAR_LISTA_ALV. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. *=====================================================* * END-OF-SELECTION * *=====================================================* END-OF-SELECTION. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. PERFORM BUILD_SORT. *=====================================================* * END-OF-SELECTION * *=====================================================* END-OF-SELECTION. PERFORM INIT_LAYOUT. GS_SORT TYPE SLIS_T_SORTINFO_ALV. G_REPID TYPE SY-REPID. 297 .

<FS_SORT>-FIELDNAME = 'ID_PROG'. el tercero blanco. APPEND INITIAL LINE TO GS_SORT ASSIGNING <FS_SORT>. FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = 'X'. es decir. " BUILD_SORT Primero. indicamos el nombre del campo relacionado a dicha columna. indicamos el número de la columna por la cual vamos a ordenar la lista. etc. FORM FORMATEAR_DATOS_ALV_DET USING T_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. segundo. el segundo gris. " INIT_LAYOUT Indicamos que queremos que el reporte se muestre con colores intercalados por registro. ENDFORM. el primero blanco. <FS_SORT>-UP = 'X'. finalmente indicamos que la ordenación va a ser ascendente. 298 .Vamos a crear y analizar cada una de estas funciones. ENDFORM. FORM BUILD_SORT. <FS_SORT>-SPOS = 1.

L_FIELDCAT-OUTPUTLEN = 10. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-OUTPUTLEN = 15. L_FIELDCAT-COL_POS = 2. APPEND L_FIELDCAT TO T_FIELDCAT.DATA: L_FIELDCAT TYPE SLIS_FIELDCAT_ALV. 299 . CLEAR L_FIELDCAT. L_FIELDCAT-SELTEXT_L = 'Nombre Lenguaje'. L_FIELDCAT-FIELDNAME = 'NOMBRE'. L_FIELDCAT-SELTEXT_L = 'Entorno'. L_FIELDCAT-FIELDNAME = 'ID_PROG'. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-OUTPUTLEN = 15. L_FIELDCAT-COL_POS = 1. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-COL_POS = 4. CLEAR L_FIELDCAT. L_FIELDCAT-FIELDNAME = 'ENTORNO'. APPEND L_FIELDCAT TO T_FIELDCAT. APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-COL_POS = 3. L_FIELDCAT-FIELDNAME = 'NOM_PROG'. L_FIELDCAT-SELTEXT_L = 'Id'. L_FIELDCAT-OUTPUTLEN = 5. L_FIELDCAT-SELTEXT_L = 'Nombre Programa'. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'.

APPEND L_FIELDCAT TO T_FIELDCAT. L_FIELDCAT-FIELDNAME = 'CONEX_SAP'. de que tamaño deben de ser mostrados. En este ejemplo hemos utilizado pocos campos. Con todos los ingredientes listos. esta es apendada a la tabla T_FIELDCAT. OUTPUTLEN es la cantidad de caracteres de salida. L_FIELDCAT-SELTEXT_L = 'Conexión con SAP'. el ALV soporta hasta 65 campos sin ningún problema. 300 . FIELDNAME es el nombre del campo que queremos mostrar. puesto que indica que campos deben leerse. solo nos falta llamar al ALV. L_FIELDCAT-COL_POS = 5. y hasta donde mi experiencia personal ha llegado. "FORMATEAR_DATOS_ALV_DET La tabla L_FIELDCAT se llena con todos los campos que queremos mostrar en nuestro ALV. APPEND L_FIELDCAT TO T_FIELDCAT. y que texto va a describirlos en la cabecera. CLEAR L_FIELDCAT. COL_POS es la posición que va a tener el campo dentro del ALV. en que posición. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. Este FORM es el más importante. SELTEXT_L es el texto que se va a mostrar en el campo. L_FIELDCAT-OUTPUTLEN = 15. TABNAME es el nombre de la tabla que contiene la estructura del ALV. ENDFORM. que luego es usada para llenar la tabla I_FIELDCAT que se pasa finalmente al ALV.

G_PROGRAM = SY-REPID. CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE = ' ' I_CALLBACK_PROGRAM = G_PROGRAM I_GRID_TITLE = G_TITULO IS_LAYOUT = GS_LAYOUT IT_FIELDCAT = I_FIELDCAT IT_SORT = GS_SORT[] TABLES T_OUTTAB = T_PROGRAMAS EXCEPTIONS PROGRAM_ERROR = 1 OTHERS = 2. " F_GENERAR_LISTA_ALV G_PROGRAM es el programa al cual está enlazado el ALV. ENDFORM. G_TITULO es el título que va a llevar el listado ALV. ENDIF. EXIT.FORM F_GENERAR_LISTA_ALV. (Esta variable se asigna al parámetro I_GRID_TITLE). G_TITULO = 'Lista de Programas'. IF SY-SUBRC <> 0. (Esta variable se asigna al parámetro I_CALLBACK_PROGRAM. 301 .

(Esta tabla se asigna al parámetro IT_FIELDCAT). (Esta tabla se asigna al parámetro T_OUTTAB). (Esta tabla se asigna al parámetro IS_LAYOUT). podemos ejecutar el programa. I_FIELDCAT almacena los campos que conforman el ALV. 302 . Ahora. (Esta tabla se asigna al parámetro IT_SORT).GS_LAYOUT almacena el formato del listado. T_PROGRAMAS es la tabla que almacena todos los registros obtenidos en el INNER JOIN. GS_SORT almacena el orden del ALV.

sino a varias que muestren mayor información. así que cambiamos el comando. 303 . Supongamos que no queremos que sea de tipo ZEBRA. y con esto no me refiero a una línea como en el caso anterior. se nota bastante la diferencia. investigemos un poco.Ahora que ya vimos como es un ALV. Tenemos que agregar dos tabla nuevas que almacenen los título que vamos a mostrar en la cabecera. " INIT_LAYOUT Como podrán ver. ENDFORM. FORM INIT_LAYOUT. Agregando una Cabecera al Reporte Supongamos que queremos agregar una cabecera que muestre información en el ALV. GS_LAYOUT-ZEBRA = ' '.

GS_LIST_TOP_OF_PAGE almacena los título de la cabecera. mientras que I_EVENT controla los eventos del ALV. PERFORM F_FORMATEAR_EVENTOS_ALV USING I_EVENTS[]. PERFORM F_FORMATO_PAGE CHANGING GT_LIST_TOP_OF_PAGE. *=====================================================* * END-OF-SELECTION * *=====================================================* END-OF-SELECTION. PERFORM INIT_LAYOUT. Además necesitamos dos nuevas funciones. 304 . PERFORM F_GENERAR_LISTA_ALV. FORM F_FORMATO_PAGE CHANGING GT_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. I_EVENTS TYPE SLIS_T_EVENT. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. F_FORMATO_PAGE nos permite definir el texto de la cabecera.*=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. PERFORM BUILD_SORT.

GS_LINE-INFO es el texto que se va a mostrar. FORM F_FORMATEAR_EVENTOS_ALV USING P_EVENTS TYPE SLIS_T_EVENT. ENDFORM. CONCATENATE 'HORA:' SY-UZEIT INTO GS_LINE-INFO SEPARATED BY SPACE. DATA: L_EVENTS TYPE SLIS_ALV_EVENT. APPEND GS_LINE TO GT_TOP_OF_PAGE. CONCATENATE 'FECHA:' SY-DATUM INTO GS_LINE-INFO SEPARATED BY SPACE. CLEAR GS_LINE. CLEAR GS_LINE. GS_LINE-TYP = 'H'. Mientras que el segundo. 305 . GS_LINE se adiciona a la tabla GT_TOP_OF_PAGE. nos permite definir el evento que requiere el ALV para poder activar la cabecera. GS_LINE-TYP = 'H'. DATA: GS_LINE TYPE SLIS_LISTHEADER. "F_FORMATO_PAGE GS_LINE-TYP es el tipo de cabecera. APPEND GS_LINE TO GT_TOP_OF_PAGE. H equivale a Header (Cabecera).

FORM TOP_OF_PAGE. "TOP_OF_PAGE La función REUSE_ALV_COMMENTARY_WRITE es la coloca el título en el ALV. Y como utilizamos una función que crea el ALV. Para terminar. la cabecera del ALV. CLEAR L_EVENTS. "F_FORMATEAR_EVENTOS_ALV Declaramos una variable llamada L_EVENTS que controla los eventos. L_EVENTS-NAME = 'TOP_OF_PAGE'. queremos que el evento sea TOP_OF_PAGE es decir. L_EVENTS-FORM = 'TOP_OF_PAGE'. ENDFORM. En este caso. CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE' EXPORTING IT_LIST_COMMENTARY = GT_LIST_TOP_OF_PAGE. debemos indicarle que evento tiene que ser activado. FORM F_GENERAR_LISTA_ALV. un último FORM que asigna la cabecera al ALV. APPEND L_EVENTS TO P_EVENTS. ENDFORM. 306 . G_PROGRAM = G_TITULO = SY-REPID.

ENDFORM. " F_GENERAR_LISTA_ALV Debemos agregar el parámetro IT_EVENTS que recibe la tabla I_EVENTS. ENDIF. podremos ver esto. EXIT. CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE = ' ' I_CALLBACK_PROGRAM = G_PROGRAM I_GRID_TITLE = G_TITULO IS_LAYOUT = GS_LAYOUT IT_FIELDCAT = I_FIELDCAT IT_SORT = GS_SORT[] IT_EVENTS = I_EVENTS TABLES T_OUTTAB = T_PROGRAMAS EXCEPTIONS PROGRAM_ERROR = 1 OTHERS = 2. Ahora. 307 . que contiene los detalles del evento. G_TITULO = 'Lista de Programas'. cuando lo ejecutamos. IF SY-SUBRC <> 0.

DATA: GS_LINE TYPE SLIS_LISTHEADER. y concatenarlos utilizando separadores tales como “/” y “. FORM F_FORMATO_PAGE CHANGING GT_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. para luego asignarlos a nuestra tabla de cabecera. Simplemente debemos de crear dos variables de tipo texto.”. Podemos corregirlos de una manera muy sencilla.Claro que la fecha y lo hora se ven bastante mal. FECHA(10) TYPE C. CONCATENATE SY-DATUM+6(2) SY-DATUM+4(2) SY-DATUM+0(4) INTO FECHA SEPARATED BY '/'. obtener los componentes de la fecha y la hora. CONCATENATE SY-UZEIT+0(2) SY-UZEIT+2(2) SY-UZEIT+4(2) 308 . esto es porque se muestran en el formato interno de SAP. HORA(10) TYPE C.

309 . CLEAR GS_LINE. APPEND GS_LINE TO GT_TOP_OF_PAGE. "F_FORMATO_PAGE El nuevo ALV se vería así. CONCATENATE 'HORA:' HORA INTO GS_LINE-INFO SEPARATED BY SPACE. CONCATENATE 'FECHA:' FECHA INTO GS_LINE-INFO SEPARATED BY SPACE. CLEAR GS_LINE. GS_LINE-TYP = 'H'. APPEND GS_LINE TO GT_TOP_OF_PAGE. ENDFORM. INTO HORA SEPARATED BY ':'. GS_LINE-TYP = 'H'.

G_TITULO TYPE SY-TITLE. debemos asignar un código de función. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: G_PROGRAM TYPE SY-REPID. GS_SORT TYPE SLIS_T_SORTINFO_ALV. debemos agregar una nueva variable para manejar este evento. que es el nombre del evento que va a manejar. 310 . Y este evento “clic” es muy importante. También. vamos a definir el evento “clic” y después un par de ejemplos de su aplicación. De nuevo. G_REPID TYPE SY-REPID. hacer clic en una fila. como por ejemplo. Primero que nada.Eventos ALV Grid Una de las grandes ventajas de los ALV’s es que nos permiten realizar varias tareas relacionadas a eventos. puesto que nos permite interactuar con el registro que hemos seleccionado. G_USER_COMMAND TYPE SLIS_FORMNAME VALUE 'USER_COMMAND'. La variable G_USER_COMMAND tiene el valor por defecto USER_COMMAND.

FORM INIT_LAYOUT. READ TABLE T_PROGRAMAS INDEX RS_SELFIELD-TABINDEX 311 . DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. debemos declarar un nuevo Field-Symbol. ENDFORM. CASE R_UCOMM. WHEN 'FUNCION'. FORM USER_COMMAND USING R_UCOMM LIKE SY-UCOMM RS_SELFIELD TYPE SLIS_SELFIELD. Debemos crear una nueva función para poder establecer cual va a ser la acción ha tomar por el ALV cuando el usuario haga doble clic sobre un registro. " INIT_LAYOUT GS_LAYOUT-F2CODE guarda el nombre que le asignamos al código de función que en este caso es “FUNCION”. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT. Antes de empezar. CHECK NOT RS_SELFIELD-TABNAME IS INITIAL. <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'.

Cuando el código de función que hemos definido. ENDCASE. ASSIGNING <FS_PROGRAMAS>. debemos primero asignar un nuevo valor a nuestra función creadora de ALV’s. es decir. "USER_COMMAND Declaramos una variable MENSAJE la cual va a contener el texto que queremos mostrar al hacer doble clic en una línea. ENDFORM. Leemos la tabla interna con el índice del registro seleccionado. 312 . CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-NOMBRE INTO MENSAJE SEPARATED BY SPACE. que hayamos seleccionado un registro. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. es decir “FUNCION”. Como era de esperarse. Revisamos que la tabla RS_SELFIELD-TABNAME no esté vacía. podemos continuar. Concatenamos algunos campos de la tabla en nuestra variable MENSAJE y llamamos a la función MESSAGE_TEXT_DISPLAY_WITH_PARA que muestra un mensaje en la pantalla.

IF SY-SUBRC <> 0. 313 . G_PROGRAM = G_TITULO = SY-REPID. CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE = ' ' I_CALLBACK_PROGRAM = G_PROGRAM I_GRID_TITLE = G_TITULO IS_LAYOUT = GS_LAYOUT I_SAVE = 'A' IT_FIELDCAT = I_FIELDCAT IT_SORT = GS_SORT[] IT_EVENTS = I_EVENTS I_CALLBACK_USER_COMMAND = G_USER_COMMAND TABLES T_OUTTAB = T_PROGRAMAS EXCEPTIONS PROGRAM_ERROR = 1 OTHERS = 2. a este parámetro le pasamos la variable G_USER_COMMAND. G_TITULO = 'Lista de Programas'.FORM F_GENERAR_LISTA_ALV. EXIT. ENDIF. ENDFORM. " F_GENERAR_LISTA_ALV Agregamos el parámetro I_CALLBACK_USER_COMMAND que permite hacer que funcionen los eventos.

Si queremos hacer un solo clic.El parámetro I_SAVE = ‘A’ nos permite manejar las variantes. GS_LAYOUT-KEY_HOTSPOT = 'X'. " INIT_LAYOUT GS_LAYOUT-KEY_HOTSPOT indica que los campos pueden ser del tipo enlace. Cuando ejecutamos el programa. bastará con hacer un doble clic en cualquier registro para ejecutar el evento. FORM INIT_LAYOUT. Hacemos lo siguiente. GS_LAYOUT-ZEBRA = ' '. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_LAYOUT-F2CODE = 'FUNCION'. 314 . podemos entonces mejorar un poco el reporte. ENDFORM.

Pintemos con colores Aunque esto no es muy común. L_FIELDCAT-SELTEXT_L = 'Id'. L_FIELDCAT-FIELDNAME = 'ID_PROG'. L_FIELDCAT-COL_POS = 1. pintar un registro. L_FIELDCAT-KEY = 'X'. lo que vamos a hacer es pintar un registro de algún color. Como pueden ver. los valores del campo ID_PROG. El L_FIELDCAT-KEY indica que este campo va a ser de tipo enlace. APPEND L_FIELDCAT TO T_FIELDCAT. necesitamos modificar un poco nuestra tabla interna. una celda. Para esto. una fila. están subrayados. lo cual indica que son campos claves para la activación con un clic por parte del usuario. 315 . L_FIELDCAT-OUTPUTLEN = 5. es decir. puede ser que alguna vez tengamos que pagar un ALV de colores. Primero.

NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. LINE_COLOR(4) TYPE C. <FS_PROGRAMAS>-LINE_COLOR = 'C510'. Agregamos un campo llamado LINE_COLOR que determina el color que queremos utilizar. ID_PROG TYPE ZPROGRAMAS-ID_PROG. MODIFY T_PROGRAMAS FROM <FS_PROGRAMAS>. ENDIF. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. debemos determinar que línea debe pintarse. Luego de obtener los datos. SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP INTO TABLE T_PROGRAMAS FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ID_PROG IN S_IDPROG. FORM OBTENER_DATOS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. 316 . END OF TY_PROGRAMAS. IF <FS_PROGRAMAS>-NOMBRE EQ 'RUBY'. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>.*=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP.

" INIT_LAYOUT Como ven. GS_LAYOUT-INFO_FIELDNAME = 'LINE_COLOR'. así que espero les sirva también a ustedes. 317 . FORM INIT_LAYOUT. GS_LAYOUT-F2CODE = 'FUNCION'. aunque no necesariamente útil. ENDFORM. " OBTENER_DATOS Si el registro tiene el valor “RUBY” en el campo NOMBRE. Finalmente. entonces pintamos la línea de verde utilizando el código C510. es bastante sencillo. pero ya me tocado hacerlo en algún proyecto. ENDLOOP. GS_LAYOUT-KEY_HOTSPOT = 'X'. GS_LAYOUT-ZEBRA = ' '. ENDFORM. debemos indicar que queremos pintar una línea.

CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. es decir. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS_AUX.Ahora que ya estamos felices con nuestro colorido ALV. podemos pasar a algo un poco más complicado. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. COLOR_CELL TYPE LVC_T_SCOL. END OF TY_PROGRAMAS. una tabla interna que tiene como campo a otra tabla interna. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. pero simple de todos modos. Vamos a colorear celdas individuales en un ALV. 318 . TYPES: BEGIN OF TY_PROGRAMAS. END OF TY_PROGRAMAS_AUX. ID_PROG TYPE ZPROGRAMAS-ID_PROG. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. Primero. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. tenemos que crear una tabla interna auxiliar y modificar un poco la tabla que teníamos. ID_PROG TYPE ZPROGRAMAS-ID_PROG. esto porque al menos en el NetWeaver no se pueden hacer SELECT’s a una tabla interna con DEEP STRUCTURE.

I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. una tabla interna dentro de nuestra tabla interna. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. <FS_PROGRAMAS> LIKE LINE OF 319 . Y agregamos un nuevo Field-Symbol. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT. WA_COLOR TYPE LVC_S_SCOL.Debemos crear un nuevo TYPES. WA_COLOR y IT_COLOR nos sirven para almacenar algunos parámetros adicionales necesarios para el color de la celda. GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS_AUX. Creamos una tabla interna basada en nuestro nuevo TYPE. I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. I_EVENTS TYPE SLIS_T_EVENT. y modificar el original agregando el campo COLOR_CELL que es en realidad. IT_COLOR TYPE TABLE OF LVC_S_SCOL.

T_PROGRAMAS. APPEND WA_COLOR TO IT_COLOR. SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP INTO TABLE T_PROGRAMAS_AUX FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ID_PROG IN S_IDPROG. pasar todos los campos a nuestra tabla interna original para recién poder determinar cuales son los campos que tienen que estar dibujados de algún color. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. No es dificil. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. 320 . MOVE-CORRESPONDING <FS_PROGRAMAS_AUX> TO <FS_PROGRAMAS>. debemos hacer el SELECT a nuestra tabla interna auxiliar. Primero. luego. MOVE 'NOMBRE' TO WA_COLOR-FNAME. REFRESH IT_COLOR. IF <FS_PROGRAMAS_AUX>-NOMBRE EQ 'RUBY'. Nuestro código va a tener que cambiar un poco. FORM OBTENER_DATOS. MOVE '6' TO WA_COLOR-COLOR-COL. LOOP AT T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. pero definitivamente quita más tiempo.

GS_LAYOUT-ZEBRA = ' '. indicándoles que ahora nos toca manejar campos y no registros. puesto que como estamos utilizando una tabla interna para contener los colores. WA_COLOR tiene una tabla DEEP llamada COLOR). ENDLOOP. 321 . <FS_PROGRAMAS>-COLOR_CELL[] = IT_COLOR[]. Asignamos el color que queremos para la celda (En este caso. debemos utilizar los atributos del Layout. en ese caso. ENDFORM. 6 es rojo) a la tabla WA_COLOR-COLOR-COL (Como ven. Finalmente. asignamos la tabla IT_COLOR al DEEP STRUCTURE COLOR_CELL de nuestra tabla original. el INIT_LAYOUT también cambia. " OBTENER_DATOS Debemos asignar el nombre del campo que se va a colorear a la tabla WA_COLOR-FNAME. FORM INIT_LAYOUT. Asignamos los registros de la tabla auxiliar a la tabla original y verificamos si el campo NOMBRE es igual a “RUBY”. ENDIF. Apendamos WA_COLOR a la tabla IT_COLOR. GS_LAYOUT-COLTAB_FIELDNAME = 'COLOR_CELL'. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'.

es decir. sería bueno que también conocieramos un poco de su barra de menús. " INIT_LAYOUT El campo COLTAB_FIELDNAME indica el tipo de evento que se va a aplicar a la columna de la lista. por lo cual. Ahora que ya sabemos como jugar con los eventos y con algunas propiedades del ALV. que además de ser Standard.ENDFORM. nos brinda toda la funcionalidad que podamos necesitar. tenemos las siguientes. El ALV quedaría así. en este caso “COLOR_CELL”. pintar una celda. Barra de Menús del ALV Entre las opciones standard que nos ofrece el ALV. muy rara vez tendremos que agregar botones adicionales. 322 .

A Æ Permite mostrar una línea del reporte B Æ Orden Ascendente C Æ Orden Descendente 323 .

D Æ Permite crear filtros adicionales E Æ Presentación Preliminar de Impresión 324 .

F Æ Abre Microsoft Excel G Æ Abre Microsoft Word H Æ Fichero local 325 .

I Æ Destinatario de Correo 326 .

J Æ Función Gráfica K Æ Modificar Disposición 327 .

L Æ Seleccionar Disposición M Æ Grabar disposición 328 .

N Æ Información 329 .

es una serie de reglas. A partir de la versión 4. ¿Qué es la Orientación a Objetos? La Programación Orientada a Objetos. sino que por el contrario. sentencias y liniamientos que se deben seguir para poder moldear procesos del mundo real. nos estamos refiriendo. ha ganado funcionalidades que le permite continuar siendo el lenguaje de programación más poderoso para el desarrollo de aplicaciones de ERP’s (Enterprise Resource Planning). lo cual permite hacerse dueños de muchos de los puntos importantes que conforman el paradigma de la orientación a objetos u OOP (Object Oriented Programming). Al decir que es una extensión. ABAP cuenta con una extensión del lenguage. representar situaciones y/o procesos. el ABAP ha evolucionado para mejor. 330 .ABAP Orientado a Objetos Introducción Al igual que todos los productos de SAP. a que el ABAP no ha sido reemplazado.6D. con la POO nosotros podemos de una manera más clara y sencilla. Es decir.

es simplemente un pedazo de código que define objetos y que define sus propiedades y métodos. La capa privada. esto no ocurre en los escenarios reales. solo puede ser accedida por los objetos creados a partir de la misma clase.Existen muchos puntos que debemos conocer primero y que son análogos en casi todos los lenguajes de programación orientados a objetos.. con ejemplos sencillos que ayuden a adquirir una base sólida para programar con este nuevo modelo de negocio. ABAP Objects no es la excepción.. no es imperativo desarrollar aplicaciones 100% OO. Las clases se componen de dos capas. Cabe destacar. • Clase: Una clase.Sino tal vez un 60-40% sería suficiente (Dependiendo del caso. y por supuesto. Una vez que conozcamos estos conceptos. una pública y otra privada (Que puede ser PRIVATE o PROTECTED). que si bien en un escenario ideal. Muchas veces. La capa pública puede ser accedida por cualquier usuario. En la capa privada. podremos ahondar en el ABAP Objects. toda la programación debería ser orientada a objetos. Las clases pueden ser definidas localmente en un programa o de modo global a 331 . Conceptos básicos de la POO Los conceptos más importantes de la POO son. se utiliza una combinación de ambas fuerzas. y que puedan ser accesados a través de métodos públicos. Por lo cual. claro está). se guardan las propiedades de los objetos para poder encapsularlos.

de instancia y estáticos. Las clases poseen dos fases importantes. Los atributos estáticos no requieren de un objeto para poder ser utilizados. De igual manera. 332 . Las clases están compuestas por diferentes secciones: o Atributos Æ Son los datos internos dentro de una clase. través de la transacción SE24 (Class Builder). Pueden ser definidos como cualquier tipo de dato ABAP. existen métodos de instancia (Pueden acceder a todos los atributos de la clase) y métodos estáticos (Solamente pueden acceder a los atributos estáticos de la clase). Son muy parecidos a los módulos de función. es necesario crear un objeto. Pueden acceder a todos los atributos de una clase y por lo tanto modificarlos. La primera es la de Definición (Es donde se declaran los atributos y los métodos) y la segunda es la de Implementación (En donde se define cual va a ser la funcionalidad de cada método). Un pequeño ejemplo de una clase. Existen dos tipos de atributos. o Métodos Æ Son los procedimientos de la clase. Para utilizar atributos de instancia.

PRIVATE SECTION. nuestro objeto siempre tendrá un valor gracias al constructor.*-----------------------------------------------------* * CLASS C_MATH DEFINITION * *-----------------------------------------------------* CLASS C_MATH DEFINITION. "C_MATH DEFINITION *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION * *-----------------------------------------------------* CLASS C_MATH IMPLEMENTATION. *DEFINICIÓN DE UN MÉTODO ENDMETHOD. Es decir. "C_MATH IMPLEMENTATION Las clases pueden utilizar los llamados Constructores. *IMPLEMENTACIÓN DE LA CLASE METHOD FACTORIAL. es inicializar un objeto con valores en el mismo momento que está siendo creado. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS. que lo único que hacen. si es que el programa no se lo asigna. 333 . *DEFINICIÓN DE LA CLASE PUBLIC SECTION. si un usuario no asigna un valor a la hora de ejecutar el programa. *SECCIÓN PÚBLICA DE LA CLASE METHODS: *MÉTODOS FACTORIAL. Esto es útil cuando necesitamos que el objeto tenga un valor por defecto. "FACTORIAL ENDCLASS.

"FACTORIAL ENDCLASS. Esto nos sirve para 334 . *DEFINICIÓN DE UN MÉTODO ENDMETHOD. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS.*-----------------------------------------------------* * CLASS C_MATH DEFINITION * *-----------------------------------------------------* CLASS C_MATH DEFINITION. *DEFINICIÓN DE LA CLASE PUBLIC SECTION. "C_MATH DEFINITION *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION * *-----------------------------------------------------* CLASS C_MATH IMPLEMENTATION. WRITE:/ NAME. que no es más que crear una clase a partir de otra existente. *IMPLEMENTACIÓN DE LA CLASE METHOD CONSTRUCTOR. PRIVATE SECTION. *SECCIÓN PÚBLICA DE LA CLASE METHODS: *MÉTODOS CONSTRUCTOR IMPORTING NAME TYPE STRING. "C_MATH IMPLEMENTATION Las clases pueden ser definidas utilizando Herencias. "CONSTRUCTOR METHOD FACTORIAL. *ENVIAMOS EL PARÁMETRO AL CONSTRUCTOR DE LA CLASE ENDMETHOD. FACTORIAL.

ENDCLASS. *-----------------------------------------------------* * CLASS C_SUPERMATH DEFINITION * *-----------------------------------------------------* CLASS C_SUPERMATH DEFINITION. pero le agregó una funcionalidad adicional.agregar funcionalidades que queremos que se encuentren separadas. nosotros podemos crear una clase que obtenga el número de factura de un pedido. haciéndolas distintas e independientes. "C_SUPERMATH DEFINITION *Definición de la clase *-----------------------------------------------------* * CLASS C_MATH DEFINITION * *-----------------------------------------------------* CLASS C_MATH DEFINITION INHERITING FROM C_SUPERMATH . una se creó heredando características de la primera. y podemos crear otra clase que herede de nuestra clase factura. *Hereda de C_SUPERMATH PUBLIC SECTION. La clase que brinda su funcionalidad. Así. Una Sub Clase se define de la siguiente manera. nos de la posibilidad de obtener la cuenta contrato de dicha factura. *Sección Pública de la clase METHODS: *Métodos FACTORIAL. tenemos dos clases. Es decir. es llamada una Sub Clase. pero que además. 335 . es llamada una Super Clase y la que ha heredado dichas funcionalidades.

*Definimos un tipo de dato que se *referiencia a la clase C_MATH DATA DESCR_REF TYPE REF TO C_MATH. *IMPLEMENTACIÓN DE LA CLASE METHOD FACTORIAL. CREATE OBJECT DESCR_REF. Cada objeto creado a partir de una clase. se comporta como un elemento completamente independiente de los demás. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS. "C_MATH IMPLEMENTATION • Objeto: Los objetos son instancias de una clase. por lo cual. *DEFINICIÓN DE UN MÉTODO ENDMETHOD. Es decir. no hay preocuparse. "FACTORIAL ENDCLASS. lo hacemos de la siguiente manera. Para instanciar un objeto. PRIVATE SECTION. No existe un límite acerca de la cantidad de objetos que se pueden crear a partir de una clase. 336 . *Creamos e instanciamos un objeto *con referencia al tipo que creamos. son copias que poseen la misma funcionalidad de la clase que los creó. "C_MATH DEFINITION *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION * *-----------------------------------------------------* CLASS C_MATH IMPLEMENTATION.

SELECTION-SCREEN END OF SCREEN 101. fueron escritos utilizando el ABAP tradicional. Factorial REPORT ZDUMMY_PRIMER_PROGRAMA. PRIVATE SECTION. "FACTORIAL DEFINITION 337 . GET_RESULT RETURNING VALUE(FACT) TYPE I. los ejemplos que hemos desarrollado. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. METHODS: SET_FACT IMPORTING NUM TYPE I. PUBLIC SECTION. *-----------------------------------------------------* * CLASS FACTORIAL DEFINITION *-----------------------------------------------------* CLASS C_FACTORIAL DEFINITION. DATA FACT TYPE I. lo cual no está mal. PARAMETERS NUMBER TYPE I.Como programar en ABAP Objects Hasta ahora. vamos a ver un ejemplo reescritos en ABAP Objects. Tanto en código como con el Generador de Clases (SE24). por lo tanto. pero lo mejor es utilizar las nuevas tecnologías. CLASS-METHODS: MAIN. ENDCLASS.

ENDIF. "GET_RESULT ENDCLASS. ENDMETHOD. IF SY-SUBRC NE 0. 338 . ENDIF. DATA MY_OBJ TYPE REF TO C_FACTORIAL. "FACTORIAL IMPLEMENTATION START-OF-SELECTION. ENDMETHOD. ENDDO. IF NUM GT 0. CALL METHOD MY_OBJ->GET_RESULT. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). "MAIN METHOD SET_FACT. CALL SELECTION-SCREEN '101' STARTING AT 10 10. METHOD MAIN. DO NUM TIMES. "SET_FACT METHOD GET_RESULT. FACT = FACT * SY-INDEX. EXIT. CREATE OBJECT MY_OBJ. ME->FACT. FACT = 1. C_FACTORIAL=>MAIN( ). ENDMETHOD.*-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION. WRITE: 'El Factorial es: '.

definimos un CLASS-METHOD. METHODS: SET_FACT IMPORTING NUM TYPE I. GET_RESULT RETURNING VALUE(FACT) TYPE I. PARAMETERS NUMBER TYPE I. ENDCLASS. PUBLIC SECTION. esto para poder llamarlo desde nuestra clase. PRIVATE SECTION. pero creanme que con el tiempo uno se acostumbra y la verdad es que es lo mejor programar así. CLASS-METHODS: MAIN. Además. extraño e innecesario. Declaramos un SELECTION-SCREEN pero utilizando un tipo ventana. En la sección pública. declaramos dos métodos. Revisemos un poco el código antes de ejecutarlo. es decir. un método de instacia. DATA FACT TYPE I. "FACTORIAL DEFINITION Creamos nuestra clase C_FACTORIAL. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. *-----------------------------------------------------* * CLASS FACTORIAL DEFINITION * *-----------------------------------------------------* CLASS C_FACTORIAL DEFINITION. SELECTION-SCREEN END OF SCREEN 101.Este código se puede ver un poco complicado. SET_FACT que recibe un 339 .

parámetro NUM y GET_RESULT que retorna el valor final del programa. ENDDO. *-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION * *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION. WRITE: 'El Factorial es: '. IF NUM GT 0. 340 . ENDMETHOD. En la sección privada. FACT = FACT * SY-INDEX. IF SY-SUBRC NE 0. agregando el código a los métodos. declaramos una variable llamada FACT. FACT = 1. ENDMETHOD. EXIT. "SET_FACT METHOD GET_RESULT. "FACTORIAL IMPLEMENTATION Implementamos nuestra clase. que es la que va a tener el resultado del factorial y es la variable que va a imprimir GET_RESULT. ENDMETHOD. METHOD MAIN. DO NUM TIMES. "MAIN METHOD SET_FACT. ENDIF. CALL SELECTION-SCREEN '101' STARTING AT 10 10. "GET_RESULT ENDCLASS. ENDIF. ME->FACT.

Llamamos al método GET_RESULT para mostrar el resultado. Llamamos al método estático MAIN. con lo cual quedaría así C_FACTORIAL->FACT. START-OF-SELECTION. Llamamos al método SET_FACT pasando el valor del parámetro obtenido en la ventana del SELECTION-SCREEN. En el método GET_RESULT imprimimos el valor de la variable FACT. declaramos un objeto de la clase C_FACTORIAL. CALL METHOD MY_OBJ->GET_RESULT. pero como la variable está en la sección privada. podemos escribirlo así ME->FACT. llamamos a nuestra pantalla para poder capturar el valor ingresado por el usuario. donde ME equivale a C_FACTORIAL.En el método MAIN. En el método SET_FACT realizamos el algoritmo para determinar el factorial. 341 . y lo creamos. Felizmente. utilizamos ME->FACT para llamar a la variable. C_FACTORIAL=>MAIN( ). DATA MY_OBJ TYPE REF TO C_FACTORIAL. entonces necesitamos acceder a ella definiendo el nombre de la clase y la variable. CREATE OBJECT MY_OBJ. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). Como se darán cuenta. esto es porque este método no recibe parámetros. y para no escribir tanto. por lo cual necesita obtener el valor de la misma clase.

los números pueden ir desde el 1 hasta el 12. así que veamos que pasa si ingresamos 13.Por cuestiones de tamaño de almacenamiento de la variable. 342 .

"FACTORIAL DEFINITION Declaramos una variable llamada FLAG que nos va a servir al momento de mostrar el mensaje de resultado. DATA: FACT TYPE I. METHODS: SET_FACT IMPORTING NUM TYPE I. PUBLIC SECTION. Para esto. que permite que el programa siga funcionando a pesar del error. en donde y hasta como podríamos resolverlo. FLAG TYPE C. GET_RESULT RETURNING VALUE(FACT) TYPE I. La imagen que vemos. nos envía un error personalizado. ENDCLASS.NET. vamos a utilizar un comando llamado CATCH SYSTEM- EXCEPTION. Esta ventana. puesto que el tamaño de la variable que utilizamos no fue lo suficientemente grande como para poder almacenar el valor del factorial. CLASS C_FACTORIAL DEFINITION. PRIVATE SECTION. nos indica porque se ha producido el error. debemos hacer unas cuantas modificaciones al programa. vamos a utilizar una pequeña artimaña para que nuestro programa siga funcionando a pesar de este error. En esta caso.En este caso. El cual funciona como un TRY-CATCH en Java o . CLASS-METHODS: MAIN. 343 . un error grave en la programación). es la de un ShortDump (Es decir. se ha producido un error. cuando. para ello. y lo que hace es simplemente intentar ejecutar una sentencia y si no puede.

va a lanzar un SY-SUBRC igual a 5 en vez de una pantalla de ShortDump. En el caso de que el SY-SUBRC sea igual a 5. limpiamos nuestra variable FLAG y utilizamos un CATCH SYSTEM-EXCEPTIONS. FLAG = 'X'. entonces limpiamos la variable FACT y llenamos con “X” la variable FLAG. CLEAR FLAG. IF NUM GT 0. Obviamente. que significa que cualquier error de tipo Overflow (valor más grande que el tamaño de variable). en este caso el ARITHMETIC_ERRORS. METHOD SET_FACT. IF SY-SUBRC EQ 5. ENDIF. DO NUM TIMES. FACT = 1. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. ENDDO. 344 . ENDIF. ENDMETHOD. EXIT. FACT = FACT * SY-INDEX. FACT = 0. ENDCATCH. salimos del método utilizando la sentencia EXIT. "SET_FACT Dentro del método SET_FACT.

Ahora. imprimimos un mensaje de advertencia. IF FLAG EQ SPACE. ELSE. gracias a lo cual podríamos obtener el Factorial de un número desde cualquier programa. Si está vacía. 345 . si tiene el valor “X”. WRITE: 'Error. ME->FACT. "GET_RESULT En el método GET_RESULT. ingrese valores del 1 al 12'. veamos el mismo ejemplo pero utilizando el Generador de Clases (SE24). ENDIF. METHOD GET_RESULT. WRITE: 'El Factorial es: '. preguntamos si la variable FLAG está vacía o tiene el valor “X”. ENDMETHOD. imprimimos el valor del factorial.

346 .

un Visibility (Visibilidad) 0 Private (Privado). SET_FACT y GET_RESULT. debemos presionar el botón Parameters (Parámetros) . nos dirigimos a la pestaña Methods (Métodos). Luego. debemos ir a la pestaña Attributes (Atributos) para declarar nuestras variables. ambos con Nivel 0 Atributo de Instacia y Visibilidad 2 Public (Pública). Declaramos dos métodos. Para asignar los parámetros.Primero. 347 . Ambas variables tiene un Level (Nivel) 0 Instance Attribute (Atributo de Instacia).

Para poder asignarles código a los métodos.SET_FACT tiene el parámetro NUM de tipo IMPORTING. GET_RESULT tiene el parámetro FACT de tipo RETURNING. debemos posicionarnos sobre cada uno de ellos y presionar el botón Code . 348 .

ENDCATCH. ME->FACT. ingrese valores del 1 al 12'. presionamos el botón Test o presionamos F8 . solo nos queda grabar. WRITE: 'Error. DO NUM TIMES. ENDDO. endmethod. pero claro. endmethod. FACT = FACT * SY-INDEX. ENDIF. method GET_RESULT. WRITE: 'El Factorial es: '. IF NUM GT 0. activar. FLAG = 'X'. CLEAR FLAG. ELSE. FACT = 0. ENDIF. Con esto. EXIT. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. ENDIF. method SET_FACT. IF FLAG EQ SPACE. Para esto. 349 .Escribimos los códigos para cada método. La clase está lista para ser utilizada. IF SY-SUBRC EQ 5. FACT = 1. lo mejor es probarlo antes.

ejecutamos el método GET_RESULT. lo ejecutamos presionando el botón Execute Method (Ejecutar Método) .Como sabemos que SET_FACT es el método que recibe el valor ingreado por el usario. De vuelta en la pantalla principal. 350 . Ingresamos un valor de prueba y presionamos el botón Execute (Ejecutar) o presionamos F8 .

A pesar de que el valor de FACT aparece como 0. ahora. PARAMETERS NUMBER TYPE I. SELECTION-SCREEN END OF SCREEN 101. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. simplemente debemos retroceder para ver el resultado. Listo. 351 . ya podemos utilizar nuestra nueva clase en un programa. REPORT ZDUMMY_PRIMER_PROGRAMA.

DATA MY_OBJ TYPE REF TO ZFACTORIAL. Ejecutamos y veremos que el resultado es el mismo. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). CALL METHOD MY_OBJ->GET_RESULT. IF SY-SUBRC NE 0. aunque el código es mucho más corto y reutilizable. ENDIF. CALL SELECTION-SCREEN '101' STARTING AT 10 10. CREATE OBJECT MY_OBJ. EXIT.START-OF-SELECTION. 352 .

CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. END OF TY_PROGRAMAS. 353 . GT_FIELDCAT TYPE LVC_T_FCAT. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ID_PROG TYPE ZPROGRAMAS-ID_PROG. GT_SORT TYPE LVC_T_SORT. GS_VARIANT TYPE DISVARIANT. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. pero ahora veremos como se hace con ABAP Objects.Componentes Orientados a Objetos Crear un ALV Grid OO Ya vimos como crear un ALV. GS_LAYOUT TYPE LVC_S_LAYO. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS.

PERFORM FILL_CATALOG. SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP INTO TABLE T_PROGRAMAS FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ). CALL SCREEN 0100.*=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: MYCONTAINER TYPE SCRFNAME VALUE 'CUSTOM_ALV'. PERFORM FILL_LAYOUT. X_SAVE. GRID1 TYPE REF TO CL_GUI_ALV_GRID. PERFORM LLAMAR_ALV. ENDFORM. *&----------------------------------------------------* *& Form cargar_datos * *&----------------------------------------------------* FORM CARGAR_DATOS. PERFORM CARGAR_DATOS. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. " cargar_datos 354 .

GS_FIELDCAT-REPTEXT = 'Id'. GS_FIELDCAT-COL_POS = 1. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. APPEND GS_FIELDCAT TO GT_FIELDCAT. GS_FIELDCAT-OUTPUTLEN = 15. " fill_layout *&----------------------------------------------------* *& Form fill_catalog * *&----------------------------------------------------* FORM FILL_CATALOG.*&----------------------------------------------------* *& Form fill_layout * *&----------------------------------------------------* FORM FILL_LAYOUT. GS_FIELDCAT-COL_POS = 2. CLEAR GS_FIELDCAT. GS_FIELDCAT-FIELDNAME = 'ID_PROG'. 355 . GS_LAYOUT-SEL_MODE = 'A'. GS_FIELDCAT-OUTPUTLEN = 5. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-REPTEXT = 'Nombre Programa'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. APPEND GS_FIELDCAT TO GT_FIELDCAT. ENDFORM. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. CLEAR GS_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'NOMBRE'.
GS_FIELDCAT-REPTEXT = 'Nombre Lenguaje'.
GS_FIELDCAT-COL_POS = 3.
GS_FIELDCAT-OUTPUTLEN = 15.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'ENTORNO'.
GS_FIELDCAT-REPTEXT = 'Entorno'.
GS_FIELDCAT-COL_POS = 4.
GS_FIELDCAT-OUTPUTLEN = 10.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'CONEX_SAP'.
GS_FIELDCAT-REPTEXT = 'Conexión con SAP'.
GS_FIELDCAT-COL_POS = 5.
GS_FIELDCAT-OUTPUTLEN = 15.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

ENDFORM. " fill_catalog

*&----------------------------------------------------*
*& Form llamar_alv *
*&----------------------------------------------------*
FORM LLAMAR_ALV.

IF CUSTOM_CONTAINER IS INITIAL.

356

CREATE OBJECT CUSTOM_CONTAINER
EXPORTING
CONTAINER_NAME = MYCONTAINER
EXCEPTIONS
CNTL_ERROR = 1
CNTL_SYSTEM_ERROR = 2
CREATE_ERROR = 3
LIFETIME_ERROR = 4
LIFETIME_DYNPRO_DYNPRO_LINK = 5.
ENDIF.

CREATE OBJECT GRID1
EXPORTING
I_PARENT = CUSTOM_CONTAINER.

CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY
EXPORTING
IS_VARIANT = GS_VARIANT
I_SAVE = X_SAVE
I_DEFAULT = 'X'
IS_LAYOUT = GS_LAYOUT
CHANGING
IT_FIELDCATALOG = GT_FIELDCAT
IT_SORT = GT_SORT[]
IT_OUTTAB = T_PROGRAMAS[].

CALL METHOD GRID1->SET_READY_FOR_INPUT
EXPORTING
I_READY_FOR_INPUT = 0.

ENDFORM. " llamar_alv

357

*&----------------------------------------------------*
*& Module STATUS_0100 OUTPUT *
*&----------------------------------------------------*
MODULE STATUS_0100 OUTPUT.

SET PF-STATUS '100'.
SET TITLEBAR '100'.

ENDMODULE. " STATUS_0100 OUTPUT

*&----------------------------------------------------*
*& Module USER_COMMAND_0100 INPUT *
*&----------------------------------------------------*
MODULE USER_COMMAND_0100 INPUT.

DATA: OK_CODE TYPE SY-UCOMM.

OK_CODE = SY-UCOMM.
CASE OK_CODE.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
SET SCREEN 0.
LEAVE SCREEN.
CLEAR SY-UCOMM.
ENDCASE.

ENDMODULE. " USER_COMMAND_0100 INPUT

El código no deja de ser un poco extenso, así que vamos a revisarlo
por partes. Aunque antes de continuar, hay un detalle muy
importante que debemos tener en cuenta. Debemos crear un Dynpro
asociado a esta pantalla, en donde el único componente será un

358

Custom Control (Control Personalizado) al cual llamaremos
CUSTOM_ALV.

Continuemos con el código.

*=====================================================*
* DECLARACION DE TYPES *
*=====================================================*
TYPES: BEGIN OF TY_PROGRAMAS,
ID_PROG TYPE ZPROGRAMAS-ID_PROG,
NOM_PROG TYPE ZPROGRAMAS-NOM_PROG,
NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE,
ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO,
CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP,
END OF TY_PROGRAMAS.

Declaramos un TYPE incluyendo los campos que queremos mostrar
en el ALV.

359

*=====================================================*
* DECLARACION DE TABLAS INTERNAS *
*=====================================================*
DATA: T_PROGRAMAS TYPE STANDARD TABLE
OF TY_PROGRAMAS,
GS_LAYOUT TYPE LVC_S_LAYO,
GT_FIELDCAT TYPE LVC_T_FCAT,
GT_SORT TYPE LVC_T_SORT,
GS_VARIANT TYPE DISVARIANT.

Declaramos algunas tablas internas, T_PROGRAMAS donde van a
estar los registros para el ALV, GS_LAYOUT donde vamos a
especificar como se visualiza el ALV, GT_FIELDCAT donde va a
estar el catálogo de campos, GT_SORT donde se indican los
criterios de ordenación y GS_VARIANT que indica el manejo de
variantes.
Si bien hay tablas que no vamos a utilizar, debemos declararlas y
llamarlas de todos modos, porque el ALV así nos lo exige.

*=====================================================*
* DECLARACION DE VARIABLES *
*=====================================================*
DATA: MYCONTAINER TYPE SCRFNAME VALUE 'CUSTOM_ALV',
CUSTOM_CONTAINER TYPE REF TO
CL_GUI_CUSTOM_CONTAINER,
GRID1 TYPE REF TO CL_GUI_ALV_GRID,
X_SAVE.

MYCONTAINER es un tipo de variable que guarda el nombre de
nuestro CUSTOM_CONTROL, CUSTOM_CONTAINER hace

360

referencia al contenedor del ALV, GRID1 es un objeto de la clase
CL_GUI_ALV_GRID y X_SAVE es una variable utilizada para
determinar si se graban o no las variantes y de que modo.

*=====================================================*
* START-OF-SELECTION *
*=====================================================*
START-OF-SELECTION.
PERFORM CARGAR_DATOS.
PERFORM FILL_LAYOUT.
PERFORM FILL_CATALOG.
PERFORM LLAMAR_ALV.
CALL SCREEN 0100.

Tenemos varios PERFORM’s, el primero carga los datos, el
segundo determina el formato del ALV, el tercero llena el catálogo y
el cuarto llama al ALV. Como creamos un Dynpro, debemos
llamarlo.

*&----------------------------------------------------*
*& Form cargar_datos *
*&----------------------------------------------------*
FORM CARGAR_DATOS.

SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP
INTO TABLE T_PROGRAMAS
FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG
ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ).

ENDFORM. " cargar_datos

361

Hacemos un INNER JOIN para seleccionar los datos de la tablas.

*&----------------------------------------------------*
*& Form fill_layout *
*&----------------------------------------------------*
FORM FILL_LAYOUT.

GS_LAYOUT-SEL_MODE = 'A'.

ENDFORM. " fill_layout

Establecemos el modo se selección.

*&----------------------------------------------------*
*& Form fill_catalog *
*&----------------------------------------------------*
FORM FILL_CATALOG.

DATA: GS_FIELDCAT TYPE LVC_S_FCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'ID_PROG'.
GS_FIELDCAT-REPTEXT = 'Id'.
GS_FIELDCAT-COL_POS = 1.
GS_FIELDCAT-OUTPUTLEN = 5.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'NOM_PROG'.

362

GS_FIELDCAT-REPTEXT = 'Nombre Programa'.
GS_FIELDCAT-COL_POS = 2.
GS_FIELDCAT-OUTPUTLEN = 15.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'NOMBRE'.
GS_FIELDCAT-REPTEXT = 'Nombre Lenguaje'.
GS_FIELDCAT-COL_POS = 3.
GS_FIELDCAT-OUTPUTLEN = 15.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'ENTORNO'.
GS_FIELDCAT-REPTEXT = 'Entorno'.
GS_FIELDCAT-COL_POS = 4.
GS_FIELDCAT-OUTPUTLEN = 10.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

CLEAR GS_FIELDCAT.
GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'.
GS_FIELDCAT-FIELDNAME = 'CONEX_SAP'.
GS_FIELDCAT-REPTEXT = 'Conexión con SAP'.
GS_FIELDCAT-COL_POS = 5.
GS_FIELDCAT-OUTPUTLEN = 15.
APPEND GS_FIELDCAT TO GT_FIELDCAT.

ENDFORM. " fill_catalog

Llenamos el catálogo del ALV.

363

*&----------------------------------------------------*
*& Form llamar_alv *
*&----------------------------------------------------*
FORM LLAMAR_ALV.

IF CUSTOM_CONTAINER IS INITIAL.
CREATE OBJECT CUSTOM_CONTAINER
EXPORTING
CONTAINER_NAME = MYCONTAINER
EXCEPTIONS
CNTL_ERROR = 1
CNTL_SYSTEM_ERROR = 2
CREATE_ERROR = 3
LIFETIME_ERROR = 4
LIFETIME_DYNPRO_DYNPRO_LINK = 5.
ENDIF.

CREATE OBJECT GRID1
EXPORTING
I_PARENT = CUSTOM_CONTAINER.

CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY
EXPORTING
IS_VARIANT = GS_VARIANT
I_SAVE = X_SAVE
I_DEFAULT = 'X'
IS_LAYOUT = GS_LAYOUT
CHANGING
IT_FIELDCATALOG = GT_FIELDCAT
IT_SORT = GT_SORT[]
IT_OUTTAB = T_PROGRAMAS[].

364

CALL METHOD GRID1->SET_READY_FOR_INPUT
EXPORTING
I_READY_FOR_INPUT = 0.

ENDFORM. " llamar_alv

Creamos el objeto CUSTOM_CONTAINER apuntando a nuestro
CUSTOM_CONTROL (Cuyo nombre está almacenado en la
variable MYCONTAINER).
Creamos el objeto GRID1, especificando que se debe mostrar dentro
del contenedor CUSTOM_CONTAINER.
Llamamos al método SET_TABLE_FOR_FIRST_DISPLAY
pasándole los parámetros correspondientes.
Llamamos al método SET_READY_FOR_INPUT pasando 0 como
parámetro, lo cual significa que el ALV no podrá ser modificado.

*&----------------------------------------------------*
*& Module STATUS_0100 OUTPUT *
*&----------------------------------------------------*
MODULE STATUS_0100 OUTPUT.

SET PF-STATUS '100'.
SET TITLEBAR '100'.

ENDMODULE. " STATUS_0100 OUTPUT

Establecemos el menú y el título de la aplicación.

365

*&----------------------------------------------------*
*& Module USER_COMMAND_0100 INPUT *
*&----------------------------------------------------*
MODULE USER_COMMAND_0100 INPUT.

DATA: OK_CODE TYPE SY-UCOMM.

OK_CODE = SY-UCOMM.
CASE OK_CODE.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
SET SCREEN 0.
LEAVE SCREEN.
CLEAR SY-UCOMM.
ENDCASE.

ENDMODULE. " USER_COMMAND_0100 INPUT

Definimos las acciones de los códigos de función.

Como ven, el ALV está listo para salir a producción.

366

367 . ID_PROG TYPE ZPROGRAMAS-ID_PROG. Agregamos un nuevo campos a nuestro TYPE TY_PROGRAMAS y creamos un nuevo TYPE llamado TY_NOMBRE.. claro está.. pero al mismo tiempo debemos modificar su estructura (Solamente dentro de nuestro programa...nada.Así que vamos a agregar algunas cosas adicionales.. nos vamos al Menu Painter (SE41) y agregamos un nuevo botón. Primero.. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS.Agregar validaciones y eventos Si bien el programa funciona. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.. no es muy útil que digamos puesto que no hace.) CLASS LCL_EVENT_RECEIVER DEFINITION DEFERRED.. Debemos llamar a la clase LCL_EVENT_RECIEVER.

LT_F4 TYPE LVC_T_F4 WITH HEADER LINE. GS_LAYOUT TYPE LVC_S_LAYO. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. T_NOMBRE nos sirve para crear una ayuda de búsqueda personalizada. GT_SORT TYPE LVC_T_SORT. TYPES: BEGIN OF TY_NOMBRE. END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. GS_VARIANT TYPE DISVARIANT. 368 . ID TYPE ZLENGUAJES_PROG-ID. T_NOMBRE TYPE STANDARD TABLE OF TY_NOMBRE. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. ID TYPE ZPROGRAMAS-ID. Agregamos algunas tablas internas. END OF TY_NOMBRE. T_STABLE TYPE STANDARD TABLE OF LVC_S_STBL WITH HEADER LINE. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. GT_FIELDCAT TYPE LVC_T_FCAT. RETURN_TAB TYPE STANDARD TABLE OF DDSHRETVAL WITH HEADER LINE.

EVENT_RECIEVER nos permite crear una referencia para llamar eventos en el ALV. 369 . RETURN_TAB es la tabla que nos devuelve el valor seleccionado por la función para crear ayudas de búsqueda. X_SAVE. T_STABLE nos permite que el ALV mantenga su posición al momento de actualizar los datos. L_VALID(1) TYPE C.LT_F4 nos sirve para determinar que campos van a tener asignada una ayuda de búsqueda. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: MYCONTAINER TYPE SCRFNAME VALUE 'CUSTOM_ALV'. GRID1 TYPE REF TO CL_GUI_ALV_GRID. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. W_ERROR nos indica si hay algún error en la modificación de datos. W_ERROR TYPE C. L_VALID indica si la operación es válida o no. EVENT_RECEIVER TYPE REF TO LCL_EVENT_RECEIVER. Agregamos algunas variables.

370 . *-----------------------------------------------------* * CLASS LCL_EVENT_RECEIVER DEFINITION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER DEFINITION. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_NOMBRE> LIKE LINE OF T_NOMBRE. Redefinimos la clase LCL_EVENT_RECIEVER. <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. HANDLE_DATA_CHANGED (Que valida si algún campo ha cambiado su valor) y HANDLE_F4_HELP que sirve para asignar las ayudas de búsqueda dinámicas.Agregamos algunos Field-Symbols. HANDLE_F4_HELP FOR EVENT ONF4 OF CL_GUI_ALV_GRID IMPORTING E_FIELDNAME ES_ROW_NO ER_EVENT_DATA. "LCL_EVENT_RECEIVER DEFINITION Definimos dos métodos. METHODS: HANDLE_DATA_CHANGED FOR EVENT DATA_CHANGED OF CL_GUI_ALV_GRID IMPORTING ER_DATA_CHANGED. PUBLIC SECTION. ENDCLASS.

"HANDLE_F4_HELP ENDCLASS. "LCL_EVENT_RECEIVER IMPLEMENTATION Dentro del método HANDLE_DATA_CHANGED llamamos al FORM DATA_CHANGED. Dentro del método HANDLE_F4_HELP llamamos al FORM HANDEL_ONF4. PERFORM DATA_CHANGED USING ER_DATA_CHANGED. ER_EVENT_DATA->M_EVENT_HANDLED = ‘X’.*-----------------------------------------------------* * CLASS lcl_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER IMPLEMENTATION. 371 . ER_EVENT_DATA->M_EVENT_HANDLED = 'X'. ENDMETHOD. ENDMETHOD. PERFORM HANDLE_ONF4 USING E_FIELDNAME ES_ROW_NO. *&----------------------------------------------------* *& Form cargar_datos * *&----------------------------------------------------* FORM CARGAR_DATOS. METHOD HANDLE_DATA_CHANGED. SELECT ID_PROG NOM_PROG NOMBRE ENTORNO CONEX_SAP INTO TABLE T_PROGRAMAS FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ). especificamos que queremos activar el evento. "HANDLE_DATA_CHANGED METHOD HANDLE_F4_HELP.

CLEAR GS_FIELDCAT. Dentro del catálogo. ENDFORM. SELECT ID NOMBRE INTO TABLE T_NOMBRE FROM ZLENGUAJES_PROG. GS_FIELDCAT-FIELDNAME = 'NOMBRE'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. 372 . solamente vamos a modificar un campo. *&----------------------------------------------------* *& Form llamar_alv * *&----------------------------------------------------* FORM LLAMAR_ALV. GS_FIELDCAT-COL_POS = 3. por lo que agregamos EDIT para que pueda modificarse y F4AVAILABL para que acepte la ayuda de búsqueda dinámica. esta vez a ZLENGUAJES_PROG para poder obtener los valores necesarios para nuestra ayuda de búsqueda dinámica. GS_FIELDCAT-REPTEXT = 'Nombre Lenguaje'. APPEND GS_FIELDCAT TO GT_FIELDCAT. GS_FIELDCAT-F4AVAILABL = 'X'. GS_FIELDCAT-OUTPUTLEN = 15. GS_FIELDCAT-EDIT = 'X'. " cargar_datos Agregamos un nuevo select.

IF CUSTOM_CONTAINER IS INITIAL. LT_F4-FIELDNAME = 'NOMBRE'. CALL METHOD GRID1->REGISTER_F4_FOR_FIELDS EXPORTING IT_F4 = LT_F4[]. ENDIF. 373 . CREATE OBJECT EVENT_RECEIVER. CREATE OBJECT CUSTOM_CONTAINER EXPORTING CONTAINER_NAME = MYCONTAINER EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 LIFETIME_DYNPRO_DYNPRO_LINK = 5. LT_F4-CHNGEAFTER = 'X' . SET HANDLER EVENT_RECEIVER- >HANDLE_DATA_CHANGED FOR GRID1. CREATE OBJECT GRID1 EXPORTING I_PARENT = CUSTOM_CONTAINER. LT_F4-REGISTER = 'X' . APPEND LT_F4. SET HANDLER EVENT_RECEIVER->HANDLE_F4_HELP FOR GRID1. LT_F4-GETBEFORE = 'X' .

Llenamos la tabla LT_F4. " llamar_alv Creamos el objeto EVENT_RECIEVER para poder asignar los eventos al ALV. CALL METHOD GRID1->REGISTER_EDIT_EVENT EXPORTING I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED. con el campo que tendrá la ayuda de búsqueda dinámica. Establecemos los eventos utilizando el comando SET HANDLER. 374 . CALL METHOD GRID1->SET_READY_FOR_INPUT EXPORTING I_READY_FOR_INPUT = 1. ENDIF. ENDFORM. CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_VARIANT = GS_VARIANT I_SAVE = X_SAVE I_DEFAULT = 'X' IS_LAYOUT = GS_LAYOUT CHANGING IT_FIELDCATALOG = GT_FIELDCAT IT_SORT = GT_SORT[] IT_OUTTAB = T_PROGRAMAS[]. IF SY-BATCH IS INITIAL.

PERFORM GRABAR_DATOS. ENDCASE. Validamos que los registros del ALV hayan cambiado de valor y llamamos al FORM GRABAR_DATOS para guardar los cambios en la Base de Datos. si es en modo directo. ENDMODULE. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. CASE OK_CODE. CLEAR SY-UCOMM. OK_CODE = SY-UCOMM. entonces registramos el evento de modificación. LEAVE SCREEN. *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. SET SCREEN 0. " USER_COMMAND_0100 INPUT Agregamos el código de función SAVE. DATA: OK_CODE TYPE SY-UCOMM. IF L_VALID EQ 'X'. ENDIF.La variable SY-BATCH nos indica si estamos ejecutando el programa en fondo o en modo directo. CALL METHOD GRID1->CHECK_CHANGED_DATA IMPORTING E_VALID = L_VALID. 375 . WHEN 'SAVE'.

DATA: L_NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. WHEN 'NOMBRE'. CALL METHOD RR_DATA_CHANGED->ADD_PROTOCOL_ENTRY EXPORTING I_MSGID = '0K' I_MSGNO = '000' I_MSGTY = 'E' I_MSGV1 = 'Seleccione algún nombre' I_FIELDNAME = LS_MOD_CELLS-FIELDNAME 376 . LS_MOD_CELLS TYPE LVC_S_MODI. IF L_NOMBRE IS INITIAL. CALL METHOD RR_DATA_CHANGED->GET_CELL_VALUE EXPORTING I_ROW_ID = LS_MOD_CELLS-ROW_ID I_FIELDNAME = LS_MOD_CELLS-FIELDNAME IMPORTING E_VALUE = L_NOMBRE. DATA: W_NEW.*&----------------------------------------------------* *& Form data_changed * *&----------------------------------------------------* FORM DATA_CHANGED USING RR_DATA_CHANGED TYPE REF TO CL_ALV_CHANGED_DATA_PROTOCOL. CASE LS_MOD_CELLS-FIELDNAME. LS_CELLS TYPE LVC_S_MODI. LOOP AT RR_DATA_CHANGED->MT_GOOD_CELLS INTO LS_MOD_CELLS.

CALL METHOD RR_DATA_CHANGED->ADD_PROTOCOL_ENTRY EXPORTING I_MSGID = '0K' I_MSGNO = '000' I_MSGTY = 'E' I_MSGV1 = 'Nombre ingresado no existe' I_FIELDNAME = LS_MOD_CELLS-FIELDNAME I_ROW_ID = LS_MOD_CELLS-ROW_ID. CALL METHOD RR_DATA_CHANGED->MODIFY_CELL EXPORTING I_ROW_ID = LS_MOD_CELLS-ROW_ID I_FIELDNAME = 'ID' I_VALUE = <FS_NOMBRE>-ID. W_ERROR = 'X'. I_ROW_ID = LS_MOD_CELLS-ROW_ID. ELSE. READ TABLE T_NOMBRE WITH KEY NOMBRE = L_NOMBRE ASSIGNING <FS_NOMBRE>. ENDCASE. IF SY-SUBRC NE 0. ENDIF. ENDFORM. es decir a los campos que han cambiado de 377 . W_ERROR = 'X'. ENDLOOP. ENDIF. "data_changed Hacemos un LOOP a RR_DATA_CHANGED- >MT_GOOD_CELLS. ELSE.

valor. Si no hay más problemas. pero necesitamos que a su vez se modifique también el campo ID). WHEN 'NOMBRE'. Llamamos al método GET_CELL_VALUE para validar el nuevo contenido del campo. mostramos un mensaje de error con el método ADD_PROTOCOL_ENTRY. en caso contrario leemos la tabla interna T_NOMBRE para validar que el valor exista. Si está vacío. llamamos al método MODIFY_CELL para modificar el campo ID (Puesto que nosotros hemos modificado el campo NOMBRE. *&----------------------------------------------------* *& Form handle_onf4 * *&----------------------------------------------------* FORM HANDLE_ONF4 USING P_E_FIELDNAME P_ES_ROW_NO STRUCTURE LVC_S_ROID. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD = 'NOMBRE' VALUE_ORG = 'S' TABLES VALUE_TAB = T_NOMBRE RETURN_TAB = RETURN_TAB EXCEPTIONS PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3. 378 . CASE P_E_FIELDNAME.

READ TABLE T_PROGRAMAS INDEX P_ES_ROW_NO-ROW_ID ASSIGNING <FS_PROGRAMAS>. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE ID NE SPACE. IF NOT RETURN_TAB[] IS INITIAL. ENDFORM. <FS_PROGRAMAS>-ID = <FS_NOMBRE>-ID. *&----------------------------------------------------* *& Form grabar_datos * *&----------------------------------------------------* FORM GRABAR_DATOS. ENDIF. <FS_PROGRAMAS>-NOMBRE = RETURN_TAB-FIELDVAL. Llamamos al método REFRESH_TABLE_DISPLAY para refrescar el contenido del ALV. "handle_onf4 Llamamos al método F4IF_INT_TABLE_VALUE_REQUEST para poder mostrar la ayuda de búsqueda dinámica. 379 . READ TABLE RETURN_TAB INDEX 1. CALL METHOD GRID1->REFRESH_TABLE_DISPLAY EXPORTING IS_STABLE = T_STABLE. UPDATE ZPROGRAMAS SET ID = <FS_PROGRAMAS>-ID WHERE ID_PROG EQ <FS_PROGRAMAS>-ID_PROG. READ TABLE T_NOMBRE WITH KEY NOMBRE = RETURN_TAB-FIELDVAL ASSIGNING <FS_NOMBRE>. ENDCASE.

ELSE. activamos y ejecutamos. 380 . ROLLBACK WORK. ENDIF. " GRABAR_DATOS Recorremos todos los registros de nuestra tabla interna. luego utilizamos un UPDATE para actualizar los valores de la Base de Datos. que tengan un valor en el campo ID. ENDLOOP. ENDFORM. Grabamos. IF SY-SUBRC EQ 0. COMMIT WORK.

en donde un nodo principal agrupa subnodos u hojas. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. END OF TY_PROGRAMAS. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. Este tipo de reporte no es muy utilizado. TYPES: BEGIN OF TY_HEADER. REPORT ZDUMMY_PRIMER_PROGRAMA.Crear un ALV Tree OO Un ALV Tree es un tipo de reporte jerárquico. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. Este es el código. pero de todos modos es muy intersante y vale la pena revisarlo. END OF TY_HEADER. 381 . *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG.

T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. <FS_TREE> LIKE LINE OF T_PROGRAMAS. L_HIERARCHY_HEADER TYPE TREEV_HHDR.*=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. GT_FIELDCAT_TREE TYPE LVC_T_FCAT. T_HEADER TYPE STANDARD TABLE OF TY_HEADER. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. 382 . <FS_HEADER> LIKE LINE OF T_HEADER.

APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. DELETE ADJACENT DUPLICATES FROM T_HEADER. PERFORM CARGAR_DATOS. ENDFORM. PERFORM INIT_TREE.*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. ENDLOOP. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. SORT T_HEADER. " CARGAR_DATOS 383 . LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE. CALL SCREEN 0100.

WHEN 'BACK' OR 'STOP' OR 'CANCEL'. OK_CODE = SY-UCOMM. SET PF-STATUS '100'. SET SCREEN 0. LEAVE SCREEN. CLEAR SY-UCOMM. ENDCASE. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. SET TITLEBAR '100'. " USER_COMMAND_0100 INPUT 384 .*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. CASE OK_CODE. ENDMODULE. ENDMODULE.

*&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. DATA: L_TREE_CONTAINER_NAME(30) TYPE C. L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME = L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 LIFETIME_DYNPRO_DYNPRO_LINK = 5. CREATE OBJECT G_ALV_TREE EXPORTING PARENT = G_CUSTOM_CONTAINER NODE_SELECTION_MODE = CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE ITEM_SELECTION = '' NO_HTML_HEADER = 'X' NO_TOOLBAR = '' EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 385 .

GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. LIFETIME_ERROR = 4 ILLEGAL_NODE_SELECTION_MODE = 5 FAILED = 6 ILLEGAL_COLUMN_NAME = 7. PERFORM FILL_CATALOG_TREE. CLEAR GS_FIELDCAT. CALL METHOD G_ALV_TREE->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_HIERARCHY_HEADER = L_HIERARCHY_HEADER CHANGING IT_OUTTAB = T_TREE[] IT_FIELDCATALOG = GT_FIELDCAT_TREE. PERFORM CREATE_HIERARCHY. " INIT_TREE *&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. 386 . GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. GS_FIELDCAT-OUTPUTLEN = 20. ENDFORM. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. GS_FIELDCAT-COL_POS = 1. PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER. Programa'. GS_FIELDCAT-SCRTEXT_S = 'Nom.

"fill_catalog_tree *&----------------------------------------------------* * FORM build_hierarchy_header * *&----------------------------------------------------* FORM BUILD_HIERARCHY_HEADER CHANGING P_HIERARCHY_HEADER TYPE TREEV_HHDR. "BUILD_HIERARCHY_HEADER *&----------------------------------------------------* *& Form create_hierarchy * *&----------------------------------------------------* FORM CREATE_HIERARCHY. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. GS_FIELDCAT-COL_POS = 2. P_HIERARCHY_HEADER-WIDTH = 60. L_NEXT_KEY TYPE LVC_NKEY. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. CLEAR P_HIERARCHY_HEADER. P_HIERARCHY_HEADER-HEADING = 'Código'(300). 387 . ENDFORM. ENDFORM. CLEAR GS_FIELDCAT. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. DATA: L_ROOT_KEY TYPE LVC_NKEY. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. GS_FIELDCAT-OUTPUTLEN = 15.

CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. W_MENGE_TEXT(13) TYPE C. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. ENDLOOP. ENDFORM. HEADER TYPE STRING. "CREATE_HIERARCHY *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. ENDLOOP. L_LAST_KEY TYPE LVC_NKEY. HEADER = <FS_HEADER>-LENGUAJE. 388 . PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY. CLEAR L_ROOT_KEY. CLEAR L_ROOT_KEY. LOOP AT T_HEADER ASSIGNING <FS_HEADER>. CLEAR L_NEXT_KEY.

ENDFORM. L_NODE_TEXT = L_NAME. 389 . CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD I_NODE_TEXT = L_NODE_TEXT IS_OUTTAB_LINE = LS_TREE IMPORTING E_NEW_NODE_KEY = L_NEXT_KEY. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD IS_OUTTAB_LINE = T_TREE IMPORTING E_NEW_NODE_KEY = L_LAST_KEY. "ADD_NODE *&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. DATA: L_NODE_TEXT TYPE LVC_VALUE. LS_TREE TYPE TY_PROGRAMAS.

LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE.ENDFORM. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. uno para crear la tabla que guardará los datos del ALV y otro para crear la tabla que guardará los datos de la cabecera del programa. END OF TY_HEADER. END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_HEADER. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. "ADD_LEAF Revisemos el código paso a paso. Declaramos dos TYPE’s. T_HEADER TYPE STANDARD TABLE OF 390 . LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG.

TY_HEADER. GT_FIELDCAT_TREE TYPE LVC_T_FCAT. G_ALV_TREE que es un objeto de la clase CL_GUI_ALV_TREE. L_HIERARCHY_HEADER TYPE TREEV_HHDR. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. G_CUSTOM_CONTAINER que es un contenedor para el ALV y L_HIERARCHY_HEADER que sirve para definir la cabecera. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. T_PROGRAMAS que guarda los datos del ALV. T_TREE que es una tabla intermedia para mostrar los datos del ALV. <FS_HEADER> LIKE LINE OF 391 . Declaramos algunas tablas internas. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. T_HEADER es la cabecera del ALV. Declaramos algunas variables. OK_CODE para guardar el código de función. GT_FIELDCAT_TREE es el catálogo del ALV.

CALL SCREEN 0100. Declaramos algunos Field-Symbols. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. llamamos a la pantalla 100. <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE. 392 . Llamamos dos FORM’s CARGAR_DATOS e INIT_TREE. <FS_TREE> LIKE LINE OF T_PROGRAMAS. PERFORM INIT_TREE. APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. T_HEADER. PERFORM CARGAR_DATOS. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS.

ENDMODULE. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. " CARGAR_DATOS Seleccionamos los datos de la vista ZVLENGUAJES_PROG. SET PF-STATUS '100'. SET TITLEBAR '100'. 393 . *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. CLEAR SY-UCOMM. " STATUS_0100 OUTPUT Establecemos el menú y título del programa. ENDFORM. OK_CODE = SY-UCOMM. ENDLOOP. SORT T_HEADER. Luego asignamos el campo LENGUAJE a la tabla T_HEADER y eliminamos los registros duplicados. DELETE ADJACENT DUPLICATES FROM T_HEADER.

ENDCASE. ENDMODULE. CASE OK_CODE. " USER_COMMAND_0100 INPUT Asignamos acciones para el código de funciones. *&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME = L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 LIFETIME_DYNPRO_DYNPRO_LINK = 5. CREATE OBJECT G_ALV_TREE 394 . L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. LEAVE SCREEN. DATA: L_TREE_CONTAINER_NAME(30) TYPE C. SET SCREEN 0. WHEN 'BACK' OR 'STOP' OR 'CANCEL'.

ENDFORM. EXPORTING PARENT = G_CUSTOM_CONTAINER NODE_SELECTION_MODE = CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE ITEM_SELECTION = '' NO_HTML_HEADER = 'X' NO_TOOLBAR = '' EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 ILLEGAL_NODE_SELECTION_MODE = 5 FAILED = 6 ILLEGAL_COLUMN_NAME = 7. PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER. PERFORM FILL_CATALOG_TREE. " INIT_TREE 395 . PERFORM CREATE_HIERARCHY. CALL METHOD G_ALV_TREE->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_HIERARCHY_HEADER = L_HIERARCHY_HEADER CHANGING IT_OUTTAB = T_TREE[] IT_FIELDCATALOG = GT_FIELDCAT_TREE.

GS_FIELDCAT-COL_POS = 1. 396 . donde creamos la estructura del ALV. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. Llamámos al FORM BUILD_HIERARCHY_HEADER. CLEAR GS_FIELDCAT. *&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. GS_FIELDCAT-SCRTEXT_S = 'Nom. Programa'.Creamos el contenedor G_CUSTOM_CONTAINER pasando como parámetro el nombre de nuestro CUSTOM_CONTROL contenido en la variable L_TREE_CONTAINER_NAME. Creamos el objeto G_ALV_TREE asignándolo a nuestro contenedor G_CUSTOM_CONTAINER. donde establecemos los detalles de la cabecera. Llamámos al FORM FILL_CATALOG_TREE donde llenaremos el catálogo del ALV. Finalmemte llamámos al FORM CREATE_HIERARCHY. GS_FIELDCAT-OUTPUTLEN = 20. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. Llamámos al método SET_TABLE_FOR_FIRST_DISPLAY para llamar al ALV.

CLEAR P_HIERARCHY_HEADER. GS_FIELDCAT-OUTPUTLEN = 15. "BUILD_HIERARCHY_HEADER La cabecera del ALV va a tener el título “Código”. GS_FIELDCAT-COL_POS = 2. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. P_HIERARCHY_HEADER-WIDTH = 60. *&----------------------------------------------------* *& Form create_hierarchy * 397 . APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. P_HIERARCHY_HEADER-HEADING = 'Código'(300). "fill_catalog_tree Creamos el catálogo del ALV. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. una longitud de 60. ENDFORM. CLEAR GS_FIELDCAT. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. ENDFORM. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. *&----------------------------------------------------* * FORM build_hierarchy_header * *&----------------------------------------------------* FORM BUILD_HIERARCHY_HEADER CHANGING P_HIERARCHY_HEADER TYPE TREEV_HHDR.

CLEAR L_NEXT_KEY. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. HEADER = <FS_HEADER>-LENGUAJE. CLEAR L_ROOT_KEY. L_NEXT_KEY TYPE LVC_NKEY. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. "CREATE_HIERARCHY 398 . L_LAST_KEY TYPE LVC_NKEY. DATA: L_ROOT_KEY TYPE LVC_NKEY. ENDLOOP. W_MENGE_TEXT(13) TYPE C. HEADER TYPE STRING. ENDFORM. PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. ENDLOOP. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. LOOP AT T_HEADER ASSIGNING <FS_HEADER>. PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY.*&----------------------------------------------------* FORM CREATE_HIERARCHY. CLEAR L_ROOT_KEY.

DATA: L_NODE_TEXT TYPE LVC_VALUE. Luego recorremos todos los registros de la tabla T_PROGRAMAS buscando los registros que tengan el campo LENGUAJE igual que el nodo. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD I_NODE_TEXT = L_NODE_TEXT IS_OUTTAB_LINE = LS_TREE IMPORTING E_NEW_NODE_KEY = L_NEXT_KEY. *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. esto para poder agregarlos utilizando el FORM ADD_LEAF. LS_TREE TYPE TY_PROGRAMAS. Una vez que terminamos llamámos al método FRONTEND_UPDATE para refrescar los valores del ALV. Llamamos al FORM ADD_NODE para agregar un nuevo nodo. asignamos el valor del campo LENGUAJE al campo HEADER (Esta variable dará un texto al NODO). 399 . L_NODE_TEXT = L_NAME.Recorremos los registros de la tabla T_HEADER.

Grabamos. ENDFORM. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD IS_OUTTAB_LINE = T_TREE IMPORTING E_NEW_NODE_KEY = L_LAST_KEY. *&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. "ADD_LEAF Llamámos al método ADD_NODE para crear un nuevo nodo. 400 . "ADD_NODE Llamámos al método ADD_NODE para crear un nuevo nodo. Aunque claro. pasamos otro parámetro para que se cree como subnodo.ENDFORM. activamos y ejecutamos.

G_LINE_BEHAVIOUR TYPE REF TO CL_DRAGDROP. L_HIERARCHY_HEADER TYPE TREEV_HHDR.Así que vamos a agregar algunas cosas adicionales. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. no es muy útil que digamos puesto que no hace. G_FAV_BEHAVIOUR TYPE REF TO CL_DRAGDROP. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM..Agregar validaciones y eventos Si bien el programa funciona.nada.. W_NODE_KEY TYPE LVC_NKEY. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER.. 401 .. L_LAST_KEY TYPE LVC_NKEY...

DATA: CPS_PROGRAMAS TYPE TY_PROGRAMAS. PUBLIC SECTION. W_NODE_KEY variable para almacenar el nodo que se ha movido de carpeta. *-----------------------------------------------------* * CLASS lcl_dnd_event_receiver DEFINITION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER DEFINITION. "LCL_DRAGDROPOBJ DEFINITION Definimos algunas variables de clase. CP_NODE_TEXT TYPE LVC_VALUE. *-----------------------------------------------------* * CLASS LCL_DRAGDROPOBJ DEFINITION * *-----------------------------------------------------* CLASS LCL_DRAGDROPOBJ DEFINITION.Agregamos algunas variables. PUBLIC SECTION. CP_NODE_KEY TYPE LVC_NKEY. CPS_PROGRAMAS sirve como una cabecera con los datos de los nodos. L_LAST_KEY determina el nodo padre. G_LINE_BEHAVIOUR objeto que determina que el nodo puede moverse. CP_NODE_TEXT almacena el texto del nodo y CP_NODE_KEY almacena el índice del nodo. G_FAV_BEHAVIOUR objeto que determina que el folder puede aceptar un nuevo nodo. METHODS: 402 . ENDCLASS.

"lcl_dnd_event_receiver DEFINITION Declaramos dos métodos para manejar el Drag & Drop (Arrastrar y soltar) en el ALV. HANDLE_FAV_DROP FOR EVENT ON_DROP OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY DRAG_DROP_OBJECT. METHOD HANDLE_LINE_DRAG. *-----------------------------------------------------* * CLASS lcl_dnd_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER IMPLEMENTATION. 403 . CREATE OBJECT DATAOBJ. DATAOBJ->CP_NODE_KEY = NODE_KEY. HANDLE_LINE_DRAG FOR EVENT ON_DRAG OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY FIELDNAME DRAG_DROP_OBJECT. ENDCLASS. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ. CALL METHOD SENDER->GET_OUTTAB_LINE EXPORTING I_NODE_KEY = NODE_KEY IMPORTING E_OUTTAB_LINE = DATAOBJ->CPS_PROGRAMAS E_NODE_TEXT = DATAOBJ->CP_NODE_TEXT.

ENDIF. ENDMETHOD. L_NEW_KEY TYPE LVC_NKEY. CALL METHOD SENDER->FRONTEND_UPDATE. ENDMETHOD. PERFORM ADD_LEAF USING DATAOBJ->CPS_PROGRAMAS NODE_KEY CHANGING DATAOBJ->CP_NODE_KEY. "HANDLE_FAV_DROP ENDCLASS. W_NODE_KEY = DATAOBJ->CP_NODE_KEY. IF SY-SUBRC <> 0. DRAG_DROP_OBJECT->OBJECT = DATAOBJ. ENDCATCH. CALL METHOD G_ALV_TREE->DELETE_SUBTREE EXPORTING I_NODE_KEY = W_NODE_KEY. creamos un objeto DATAOBJ y le asignamos el contenido del nodo. "HANDLE_LINE_DRAG METHOD HANDLE_FAV_DROP. "lcl_dnd_event_receiver IMPLEMENTATION En el método HANDLE_LINE_DRAG. CATCH SYSTEM-EXCEPTIONS MOVE_CAST_ERROR = 1. Con el método GET_OUTTAB_LINE llenamos las variables 404 . DATAOBJ ?= DRAG_DROP_OBJECT->OBJECT. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ. CALL METHOD DRAG_DROP_OBJECT->ABORT.

Asignamos el nodo al evento de Drag & Drop. Asignamos el evento de Drag & Drop a una variable. Llamamos al método DELETE_SUBTREE con el valor de la variable W_NODE_KEY para poder eliminar al nodo de su posición original. L_EVENT TYPE CNTL_SIMPLE_EVENT.CPS_PROGRAMAS y CP_NODE_TEXT con los valores correspondientes al nodo. PERFORM DEFINE_DND_BEHAVIOUR. En el método HANDLE_FAV_DROP. hacemos un CATCH SYSTEM-EXCEPTION por si hay algún problema al mover el nodo de una carpeta a otra. CALL METHOD G_ALV_TREE->GET_REGISTERED_EVENTS IMPORTING EVENTS = LT_EVENTS. Llamamos al FORM ADD_LEAF con el nodo que hemos movido de una carpeta a otra. Llamamos al método FRONTEND_UPDATE para actualizar el ALV. CALL METHOD G_ALV_TREE->SET_REGISTERED_EVENTS 405 . DATA: LT_EVENTS TYPE CNTL_SIMPLE_EVENTS. Asignamos el valor del nodo que hemos movido a una variable auxiliar W_NODE_KEY. L_DND_EVENT_RECEIVER TYPE REF TO LCL_DND_EVENT_RECEIVER.

EXPORTING EVENTS = LT_EVENTS EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 ILLEGAL_EVENT_COMBINATION = 3. CREATE OBJECT L_DND_EVENT_RECEIVER. L_EVENT. Las tablas internas LT_EVENTS. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. El FORM DEFINE_DND_BEHAVIOUR determina el tipo de Drag & Drop que se utilizará tanto para los nodos como para las carpetas. utilizamos los métodos GET_REGISTERED_EVENTS y SET_REGISTERED_EVENTS. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_LINE_DRAG FOR G_ALV_TREE. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_FAV_DROP FOR G_ALV_TREE. nos sirven para registrar y utilizar los eventos. Para ello. L_DND_EVENT_RECIEVER y LCL_DND_EVENT_RECIEVER. Al final de INIT_TREE. 406 . agregamos este código. Además. establecemos los Handlers (Manejadores) para los eventos HANDLE_FAV_DROP y HANDLE_LINE_DRAG.

L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_FAVOURITE_FOLDER. CALL METHOD G_FAV_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_FAVOURITE_FOLDER. L_LAYOUT_NODE-ISFOLDER = 'X'.Finalmente. LS_TREE TYPE TY_PROGRAMAS. L_NODE_TEXT = L_NAME. L_HANDLE_FAVOURITE_FOLDER TYPE I. DATA: L_NODE_TEXT TYPE LVC_VALUE. llamamos al método FRONTEND_UPDATE para actualizar el ALV. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD I_NODE_TEXT = L_NODE_TEXT IS_NODE_LAYOUT = L_LAYOUT_NODE IS_OUTTAB_LINE = LS_TREE IMPORTING E_NEW_NODE_KEY = L_NEXT_KEY. L_LAYOUT_NODE TYPE LVC_S_LAYN. *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. 407 .

*&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. nos van a ayudar para establecer que los nodos son carpetas. Pasamos el valor de la variable L_HANDLE_FAVOURITE_FOLDER hacia el campo DRAGDROPID de la variable L_LAYOUT_NODE. "ADD_NODE Modificamos un poco el FORM ADD_NODE. y que pueden aceptar un subnodo dentro de ellas. CALL METHOD G_LINE_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_LINE. asignamos el valor “X” al campo ISFOLDER de la misma variable. L_HANDLE_LINE TYPE I. además.ENDFORM. Debemos pasar el parámetro IS_NODE_LAYOUT al método ADD_NODE. DATA: L_LAYOUT_NODE TYPE LVC_S_LAYN. Las variables L_LAYOUT y L_HANDLE_FAVOURITE_FOLDER. Utilizamos el método GET_HANDLE para obtener el manejador que nos permita asignar un ID al nodo. 408 .

ENDFORM. Las variables L_LAYOUT_NODE y L_HANDLE_LINE nos va a servir para establecer que los nodos pueden moverse de una hacia otra carpeta. CREATE OBJECT G_LINE_BEHAVIOUR. Utilizando el método GET_HANDLE asignamos un manejador a la variable L_LAYOUT_NODE-DRAGDROPID. CALL METHOD G_LINE_BEHAVIOUR->ADD 409 . *&----------------------------------------------------* *& Form DEFINE_DND_BEHAVIOUR **&---------------------------------------------------* FORM DEFINE_DND_BEHAVIOUR. L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_LINE. DATA: EFFECT TYPE I. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP = CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD IS_OUTTAB_LINE = L_TREE IS_NODE_LAYOUT = L_LAYOUT_NODE IMPORTING E_NEW_NODE_KEY = L_LAST_KEY. Pasamos el parámetro IS_NODE_LAYOUT al método ADD_NODE. EFFECT = CL_DRAGDROP=>COPY. "ADD_LEAF Modificamos un poco el FORM ADD_LEAF.

CREATE OBJECT G_FAV_BEHAVIOUR. " DEFINE_DND_BEHAVIOUR Creamos dos objetos G_LINE_BEHAVIOUR y G_FAV_BEHAVIOUR. Con cada uno de ellos. determinando cual se puede arrastrar y en donde se puede soltar. cual funciona como objeto y cual como contenedor. EXPORTING FLAVOR = 'X' "#EC NOTEXT DRAGSRC = 'X' DROPTARGET = ' ' EFFECT = EFFECT. CALL METHOD G_FAV_BEHAVIOUR->ADD EXPORTING FLAVOR = 'X' "#EC NOTEXT DRAGSRC = ' ' DROPTARGET = 'X' EFFECT = EFFECT. llamaremos al método ADD. Es decir. 410 . EFFECT = CL_DRAGDROP=>COPY. ENDFORM.

*=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. una forma de crear ALV’s más orientada a objetos que la anterior (Si es que esto puede ser posible). Este es el código. el ALV hizo lo propio y ahora tenemos disponible el ALV Object Model. 411 . LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE.Crear un ALV Object Model Así como el ABAP evolucionó para mejor. ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG.

*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. T_TABLE TYPE REF TO CL_SALV_TABLE. 412 . T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. PERFORM LLAMAR_ALV. PERFORM CARGAR_DATOS. SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. END OF TY_PROGRAMAS. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS.

413 . TRY. LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ).ENDFORM. LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Programa' ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). T_DSPSET->SET_LIST_HEADER( 'Programas' ). T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). " CARGAR_DATOS *&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. T_FUNCTIONS->SET_ALL( ABAP_TRUE ). LR_COLUMN->SET_LONG_TEXT( 'Id' ). ENDTRY. CATCH CX_SALV_MSG . T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = T_TABLE CHANGING T_TABLE = T_PROGRAMAS ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ).

ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG. T_TABLE->DISPLAY( ). pero de todos modos vamos a revisarlo un poco. T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. 414 . es un código bastante pequeño. END OF TY_PROGRAMAS. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. Declaramos un TYPES con todos los campos de la vista ZVLENGUAJES_PROG. ENDFORM. " LLAMAR_ALV Como se darán cuenta. T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS. T_TABLE TYPE REF TO CL_SALV_TABLE. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE.

Bastante obvio no? *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. PERFORM LLAMAR_ALV. T_FUNCTIONS sirve para asignar las funciones de la barra de menús del ALV. Tenemos dos FORM’s CARGAR_DATOS (Donde cargamos los datos) y LLAMAR_ALV (Donde llamamos al ALV). PERFORM CARGAR_DATOS. T_DSPSET nos sirve para las opciones de visualización. T_PROGRAMAS que guardará los datos que obtengamos de la vista.. LV_SALV_COLUMNS_TABLE nos permite tomar todas las columnas de ALV. 415 . *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. T_TABLE es un parámetro para el método FACTORY y sirve para crear la estructura del ALV. SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG.. LR_COLUMN nos permite tomar las características de una columna del ALV.Declaramos varias tablas internas.

CATCH CX_SALV_MSG . LR_COLUMN->SET_LONG_TEXT( 'Id' ).ENDFORM. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = T_TABLE CHANGING T_TABLE = T_PROGRAMAS ). TRY. LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). " CARGAR_DATOS Seleccionamos todos los campos de la vista ZVLENGUAJES_PROG. LR_COLUMN->SET_LONG_TEXT( 'Programa' ). T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). T_FUNCTIONS->SET_ALL( ABAP_TRUE ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ). ENDTRY. LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). *&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. 416 .

Establecemos que queremos utilizar todas las funciones. T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). T_TABLE que contendrá la estructura del ALV y T_PROGRAMAS. el ALV no puede determinar cual es el texto que le corresponde. por lo tanto. Obtenemos las características de la columna ID_PROG. T_TABLE->DISPLAY( ). Porque hacemos esto? Pues muy simple. T_DSPSET->SET_LIST_HEADER( 'Programas' ). Utilizando LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE- >GET_COLUMN( 'ID_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Id' ). 417 . T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). pasando dos únicos parámetros. así que nos toca a nosotros asignarlo. Establecemos cual es texto de la columna. que tiene los registros obtenidos de la vista. utilizamos T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). Obtenemos todas las columnas del ALV. tanto ID_PROG como NOM_PROG no tienen asignado un elemento de datos. ENDFORM. Para obtener las funciones standard del ALV T_FUNCTIONS->SET_ALL( ABAP_TRUE ). Continuando. " LLAMAR_ALV Llamámos al método estático FACTORY de la clase CL_SALV_TABLE.

. T_DSPSET->SET_LIST_HEADER( 'Programas' )...Obtenemos las características de salida. Vamos a redefinir a la clase LCL_HANDLE_EVENTS.Así que vamos a agregar algunas cosas adicionales... Asignamos un título al reporte.nada. 418 . Llamamos y mostramos el ALV. no es muy útil que digamos puesto que no hace. T_TABLE->DISPLAY( ).. CLASS LCL_HANDLE_EVENTS DEFINITION DEFERRED. Agregar validaciones y eventos Si bien el programa funciona.

"lcl_handle_events IMPLEMENTATION Implementamos el método llamado al FORM MOSTRAR_DETALLE. ENDCLASS. PERFORM MOSTRAR_DETALLE USING ROW COLUMN. METHOD ON_DOUBLE_CLICK. T_TABLE TYPE REF TO CL_SALV_TABLE.*-----------------------------------------------------* * CLASS lcl_handle_events DEFINITION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS DEFINITION. ENDMETHOD. "on_double_click ENDCLASS. 419 . *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *-----------------------------------------------------* * CLASS lcl_handle_events IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS IMPLEMENTATION. PUBLIC SECTION. "lcl_handle_events DEFINITION Definimos un método llamado ON_DOUBLE_CLICK. METHODS: ON_DOUBLE_CLICK FOR EVENT DOUBLE_CLICK OF CL_SALV_EVENTS_TABLE IMPORTING ROW COLUMN.

*=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS. PERFORM PROCESS_EVENTS. GR_EVENTS TYPE REF TO LCL_HANDLE_EVENTS. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. Dentro de LLAMAR_ALV. agregamos el FORM PROCESS_EVENTS. 420 . Declaramos un Field-Symbol. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. que lo que va a hacer es generar el evento del Doble Clic. T_TABLE->DISPLAY( ). T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. El objeto GR_EVENTS nos permitirá registrar los eventos del ALV.

" mostrar_detalle Si hemos hecho doble clic sobre un registro de la columna NOM_PROG. ENDFORM. CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-LENGUAJE <FS_PROGRAMAS>-ENTORNO INTO MENSAJE SEPARATED BY SPACE. ENDIF. concatenamos los valores en un cadena y llamamos al módulo de funciones MESSAGE_TEXT_DISPLAY_WITH_PARA para mostrar una ventana con los datos.*-----------------------------------------------------* *& Form mostrar_detalle * *-----------------------------------------------------* FORM MOSTRAR_DETALLE USING P_ROW P_COLUMN. IF P_COLUMN EQ 'NOM_PROG'. DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. entonces leemos el registro. READ TABLE T_PROGRAMAS INDEX P_ROW ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. 421 .

DATA: LR_EVENTS TYPE REF TO CL_SALV_EVENTS_TABLE. es decir. ENDFORM. le decimos que reaccione ante el doble clic. Creamos el objeto GR_EVENTS y le asignamos el HANDLER ON_DOUBLE_CLICK. LR_EVENTS = T_TABLE->GET_EVENT( ). 422 . CREATE OBJECT GR_EVENTS.*&----------------------------------------------------* *& Form process_events * *&----------------------------------------------------* FORM PROCESS_EVENTS. obtenemos el evento definido para nuestro ALV. " process_events Utilizando el método estático GET_EVENT. SET HANDLER GR_EVENTS->ON_DOUBLE_CLICK FOR LR_EVENTS. Este sería el resultado del reporte.

LINE(255) TYPE X. creanmé que es muy útil. PICTURE TYPE REF TO CL_GUI_PICTURE. L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. pero ahora. CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_GRAPHIC_TABLE. 423 . *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE.Cargar imágenes en Dynpros Esto quizás no era muy común o requerido en los tiempos anteriores a la orientación a objetos. Este es el código. END OF TY_GRAPHIC_TABLE. GRAPHIC_SIZE TYPE I. URL(255) TYPE C. L_BYTECOUNT TYPE I.

*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. CASE OK_CODE. CLEAR SY-UCOMM. PERFORM LOAD_IMAGE. ENDMODULE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. LEAVE SCREEN. SET PF-STATUS '100'. SET SCREEN 0. OK_CODE = SY-UCOMM. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET TITLEBAR '100'. CALL SCREEN 0100. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT 424 .

CALL FUNCTION 'SAPSCRIPT_CONVERT_BITMAP' EXPORTING OLD_FORMAT = 'BDS' NEW_FORMAT = 'BMP' BITMAP_FILE_BYTECOUNT_IN = L_BYTECOUNT IMPORTING BITMAP_FILE_BYTECOUNT = GRAPHIC_SIZE 425 . CALL FUNCTION 'SAPSCRIPT_GET_GRAPHIC_BDS' EXPORTING I_OBJECT = 'GRAPHICS' I_NAME = 'ENJOY' I_ID = 'BMAP' I_BTYPE = 'BCOL' IMPORTING E_BYTECOUNT = L_BYTECOUNT TABLES CONTENT = L_CONTENT EXCEPTIONS NOT_FOUND = 1 BDS_GET_FAILED = 2 BDS_NO_CONTENT = 3 OTHERS = 4. PICTURE EXPORTING PARENT = CONTAINER1. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV'.*&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE.

CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. LINE(255) TYPE X. TABLES BDS_BITMAP_FILE = L_CONTENT BITMAP_FILE = T_GRAPHIC_TABLE EXCEPTIONS OTHERS = 1. así que será fácil entenderlo. CALL FUNCTION 'DP_CREATE_URL' EXPORTING TYPE = 'IMAGE' SUBTYPE = 'BMP' TABLES DATA = T_GRAPHIC_TABLE CHANGING URL = URL. END OF TY_GRAPHIC_TABLE. 426 . ENDFORM. CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_GRAPHIC_TABLE. " load_image Revisemos el código por partes. Es un código sencillo y corto.

L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0. PICTURE TYPE REF TO CL_GUI_PICTURE. URL almacena una dirección donde se guarda la imagen en forma temporal. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. Declaramos una tabla interna de tipo TY_GRAPHIC_TABLE. L_BYTECOUNT TYPE I. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE. CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER. OK_CODE almacena el valor del código de función.Declaramos un TYPE llamado TY_GRAPHIC_TABLE que contiene un único campo. llamado LINE de 255 caracteres y de tipo X. 427 . Esto es porque las imágenes de almacenan en formato hexadecimal. URL(255) TYPE C. GRAPHIC_SIZE TYPE I.

CONTAINER1 contiene el nombre de nuestro CUSTOM_CONTROL. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET TITLEBAR '100'. GRAPHIC_SIZE es el tamaño de la imagen luego de convetirla a BMP. L_CONTENT almacena el contenido de la imagen. PERFORM LOAD_IMAGE. PICTURE objeto que cargará y mostrará la imagen en el Dynpro. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. CALL SCREEN 0100. SET PF-STATUS '100'. ENDMODULE. " STATUS_0100 OUTPUT 428 . L_BYTECOUNT cuenta el número de bytes de la imagen que queremos visualizar. Llamamos al Dynpro 100 para mostrar la imagen.

en el FORM LOAD_IMAGE vamos a cargar la imagen en el Dynpro. PICTURE EXPORTING PARENT = CONTAINER1. CALL FUNCTION 'SAPSCRIPT_CONVERT_BITMAP' EXPORTING OLD_FORMAT = 'BDS' NEW_FORMAT = 'BMP' 429 .Llamamos a la barra de menús y al título del programa. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV'. Además. CALL FUNCTION 'SAPSCRIPT_GET_GRAPHIC_BDS' EXPORTING I_OBJECT = 'GRAPHICS' I_NAME = 'ENJOY' I_ID = 'BMAP' I_BTYPE = 'BCOL' IMPORTING E_BYTECOUNT = L_BYTECOUNT TABLES CONTENT = L_CONTENT EXCEPTIONS NOT_FOUND = 1 BDS_GET_FAILED = 2 BDS_NO_CONTENT = 3 OTHERS = 4. *&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE.

ENDFORM. CALL FUNCTION 'DP_CREATE_URL' EXPORTING TYPE = 'IMAGE' SUBTYPE = 'BMP' TABLES DATA = T_GRAPHIC_TABLE CHANGING URL = URL. 430 . CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. BITMAP_FILE_BYTECOUNT_IN = L_BYTECOUNT IMPORTING BITMAP_FILE_BYTECOUNT = GRAPHIC_SIZE TABLES BDS_BITMAP_FILE = L_CONTENT BITMAP_FILE = T_GRAPHIC_TABLE EXCEPTIONS OTHERS = 1. " load_image Creamos los objetos CONTAINER1 (Asociado a nuestro CUSTOM_CONTROL) y PICTURE (Mostrará la imagen en el contenedor).

Llamamos a la función SAPSCRIPT_CONVERT_BITMAP para convertir la imagen a un Bitmap. que en este caso es “ENJOY”. Llamamos al método LOAD_PICTURE_FROM_URL para cargar la imagen en memoria. 431 .Llamamos a la función SAPSCRIPT_GET_GRAPHIC_BDS para obtener los datos de la imagen que queremos mostrar. Llamamos a la función DP_CREATE_URL para generar una dirección donde se encuentra almacenada temporalmente la imagen BMP. Llamamos al método SET_DISPLAY_MODE para mostrar la imagen.

*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME.. CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. esto si que no creo que lo lleguen a necesitar alguna vez. PARAMETERS: FILE LIKE RLGRAP-FILENAME.. MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER.Leer PDF’s Bueno. V_URL TYPE CHAR255.Pero bueno. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. vale la pena conocerlo. 432 . W_SUBRC TYPE SY-SUBRC. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. Este es el código. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_FILETAB TYPE FILETABLE.

IF FILE IS INITIAL. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. CALL SCREEN 0100. EXIT. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.pdf' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC. FILE = <FS_FILETAB>.SELECTION-SCREEN END OF BLOCK TEST. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. 433 .pdf' FILE_FILTER = '*. ENDIF. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*.

CLEAR V_URL. ENDIF.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. CREATE OBJECT CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS CNTL_ERROR = 1 OTHERS = 2. SET TITLEBAR '100'. CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT = CONTAINER EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 OTHERS = 3. IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. V_URL = FILE. 434 . CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. IF CONTAINER IS INITIAL.

LEAVE SCREEN. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_FILETAB TYPE FILETABLE. OK_CODE = SY-UCOMM. " USER_COMMAND_0100 INPUT Revisemos un poco el código. Declaramos la tabla interna T_FILETAB de tipo FILETABLE. CLEAR SY-UCOMM. que no es más que una tabla con un campo de 1024 caracteres de longitud. ENDCASE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. 435 . ENDIF. CASE OK_CODE. ENDMODULE. SET SCREEN 0. ENDMODULE. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT.

V_URL contiene la ruta donde se encuentra el ALV. Declaramos un Field-Symbol para la tabla T_FILETAB. V_URL TYPE CHAR255. 436 . MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER.*=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. OK_CODE almacena el código de función. W_SUBRC TYPE SY-SUBRC. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. CONTAINER almacena el nombre de nuestro CUSTOM_CONTROL. W_SUBRC almacena el valor de retorno de llamar al método FILE_OPEN_DIALOG. MY_PDF_VIEWER es un objeto que nos permite visualizar un ALV. CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER.

*&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. Llamamos a la pantalla 100 de nuestro Dynpro. recogerá la ruta donde se encuentra el PDF que queremos visualizar. PARAMETERS: FILE LIKE RLGRAP-FILENAME. CALL SCREEN 0100. El evento AT-SELECION-SCREEN se ejecuta cuando llamamos al parámetro FILE. SELECTION-SCREEN END OF BLOCK TEST. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*. Este parámetro. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.pdf' 437 .*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME.

FILE = <FS_FILETAB>. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. ENDIF. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. FILE_FILTER = '*.pdf' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC. Debemos leer la tabla interna T_FILETAB y asignar su contenido al parámetro FILE. SET TITLEBAR '100'. SET PF-STATUS '100'. EXIT. IF FILE IS INITIAL. CREATE OBJECT CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS 438 . El método FILE_OPEN_DIALOG nos muestra una ventana donde podemos elegir la ubicación del archivo. IF CONTAINER IS INITIAL.

CLEAR V_URL. ENDIF. ENDIF. creamos el objeto MY_PDF_VIEWER que se mostrará dentro del objeto CONTAINER y llamamos al método OPEN_DOCUMENT para abrir el archivo PDF que cargamos. 439 . CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT = CONTAINER EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 OTHERS = 3. CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. creamos el objeto CONTAINER que hace referencia a nuesteo CUSTOM_CONTROL. ENDMODULE. " STATUS_0100 OUTPUT Además de asignar la barra de menús y el título al programa. IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. V_URL = FILE. CNTL_ERROR = 1 OTHERS = 2.

pero que definitivamente. agregan un gusto especial a la programación en ABAP. 440 .Comprimir (zip) archivos Este es otro de esos programas que no utilizaremos casi nunca. Este es el código. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: T_XLINE(2048) TYPE X.

W_SUBRC TYPE SY-SUBRC. RESULT_TAB TYPE MATCH_RESULT_TAB. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP.*=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE. W_EXT(4) TYPE C. <FS_RESULT_TAB> LIKE LINE OF RESULT_TAB. W_FILE_IN TYPE STRING. T_FILETAB TYPE FILETABLE. W_SIZE TYPE I. W_LINE TYPE STRING. 441 . PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME. OUTPUT_X TYPE XSTRING. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. INPUT_X TYPE XSTRING. SIZE TYPE I. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. W_FILE_OUT TYPE STRING.

READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. W_SIZE = W_SIZE . W_SIZE = STRLEN( W_FILE_IN ) – <FS_RESULT_TAB>-OFFSET. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME = W_FILE_IN FILETYPE = 'BIN' IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB. DESCRIBE TABLE RESULT_TAB LINES W_SIZE. 442 . FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE). SELECTION-SCREEN END OF BLOCK TEST.<FS_RESULT_TAB>-LENGTH. <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH. FILE_OUT LIKE RLGRAP-FILENAME. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.

REFRESH DATA_TAB. CALL METHOD CL_ZIP->SAVE RECEIVING ZIP = OUTPUT_X. IF CL_ZIP IS INITIAL. ENDIF. 443 .CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER = INPUT_X TABLES BINARY_TAB = DATA_TAB. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X. CREATE OBJECT CL_ZIP. CALL FUNCTION 'SCMS_XSTRING_TO_BINARY' EXPORTING BUFFER = OUTPUT_X IMPORTING OUTPUT_LENGTH = SIZE TABLES BINARY_TAB = DATA_TAB.

*&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN.*' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC. 444 . IF FILE_IN IS INITIAL. W_FILE_IN = FILE_IN.*' FILE_FILTER = '*. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME = W_FILE_OUT FILETYPE = 'BIN' CHANGING DATA_TAB = DATA_TAB. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*. CLEAR T_FILETAB. EXIT. FILE_IN = <FS_FILETAB>. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. ENDIF.

READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. Revisemos un poco el código. Nos es complicado. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*.zip' FILE_FILTER = '*. EXIT. ENDIF. W_FILE_OUT = FILE_OUT. ELSE. W_SIZE = W_SIZE . ENDIF. W_EXT = W_FILE_OUT+W_SIZE(4). IF W_EXT NE '. AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_OUT. 445 . IF FILE_OUT IS INITIAL. FILE_OUT = <FS_FILETAB>. CONCATENATE W_FILE_OUT '.zip' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC.4. W_SIZE = STRLEN( W_FILE_OUT ). FILE_OUT = W_FILE_OUT.zip'.zip' INTO W_FILE_OUT. pero algunas cosas que pueden confundir un poco a simple vista. REFRESH T_FILETAB.

Declaramos una tabla interna llamada DATA_TAB que hace referencia al TYPE T_XLINE. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP. 446 .*=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: T_XLINE(2048) TYPE X. T_FILETAB TYPE FILETABLE. es decir Hexadecimal. que nos sirve para guardar las rutas de los archivos y finalmente RESULT_TAB de tipo MATCH_RESULT_TAB. INPUT_X TYPE XSTRING. Declaramos un TYPE llamado T_XLINE de 2048 caracteres de tipo X. otra tabla llamada T_FILETAB que hace referencia a FILETABLE. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE. OUTPUT_X TYPE XSTRING. SIZE TYPE I. RESULT_TAB TYPE MATCH_RESULT_TAB. que nos sirve para almacenar las ocurrencias de una búsqueda de texto.

INPUT_X guarda el contenido de convertir el archivo de Binario a Hexadecimal (Archivo de entrada). W_FILE_IN TYPE STRING. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* 447 . W_SIZE TYPE I. W_EXT almacena la extensión del archivo de salida. W_FILE_OUT TYPE STRING. W_FILE_IN almacena la ruta del archivo de entrada. W_LINE TYPE STRING. W_FILE_OUT almacena la ruta del archivo de salida. OUTPUT_X guarda el contenido de convertir el archivo de Hexadecimal a Binario (Archivo de salida). W_SUBRC almacena el resultado de ejecutar la acción de subir los archivos. SIZE determina el tamaño del archivo que está siendo subido al servidor. W_SUBRC TYPE SY-SUBRC. W_LINE almacena el nombre final que tendrá el archivo de salida. W_SIZE almacena el tamaño en líneas de la tabla interna RESULT_TAB. CL_ZIP es un objeto que nos permitirá comprimir el documento de entrada. W_EXT(4) TYPE C.

FILE_OUT LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST. Declaramos dos parámetros.FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. 448 . <FS_RESULT_TAB> LIKE LINE OF RESULT_TAB. PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME. Declaramos dos Field-Symbols. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. uno para FILETAB y otro para RESULT_TAB. READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. uno de entrada y otro de salida. DESCRIBE TABLE RESULT_TAB LINES W_SIZE.

449 . CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME = W_FILE_IN FILETYPE = 'BIN' IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB.W_SIZE = STRLEN( W_FILE_IN ) – <FS_RESULT_TAB>-OFFSET. IF CL_ZIP IS INITIAL. CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER = INPUT_X TABLES BINARY_TAB = DATA_TAB. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X. <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH. ENDIF. CREATE OBJECT CL_ZIP. W_SIZE = W_SIZE .<FS_RESULT_TAB>-LENGTH. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE).

Leemos el último registro de la tabla RESULT_TAB utilizando como índice la cantidad de registros almacenados en la variable W_SIZE. CALL FUNCTION 'SCMS_XSTRING_TO_BINARY' EXPORTING BUFFER = OUTPUT_X IMPORTING OUTPUT_LENGTH = SIZE TABLES BINARY_TAB = DATA_TAB. 450 . Utilizamos un DESCRIBE TABLE para determinar la cantidad de registros generados y lo guardamos en W_SIZE. CALL METHOD CL_ZIP->SAVE RECEIVING ZIP = OUTPUT_X. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME = W_FILE_OUT FILETYPE = 'BIN' CHANGING DATA_TAB = DATA_TAB. Buscamos todas las ocurrencias del símbolo “\” dentro de la variable W_FILE_IN y guardamos el resultado en la tabla interna RESULT_TAB utilizando FIND ALL OCCURRENCES. REFRESH DATA_TAB.

Llamamos al método GUI_UPLOAD para subir el contenido del archivo de entrada. la longitud del símbolo “\”). Reemplazamos el valor del OFFSET. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN.Obtenemos la longitud del archivo de entrada con STRLEN y le restamos el valor OFFSET de la tabla RESULT_TAB (Este valor OFFSET es la ubicación del último símbolo “\” encontrado). Finalmente. Restamos a W_SIZE el valor del campo LENGTH. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' 451 . sumándole a este el valor del campo LENGTH (Es decir. Con el método SCMS_XSTRING_TO_BINARY convertimos el archivo ZIP de Hexadecimal a Binario y finalmente llamamos al método GUI_DOWNLOAD para descargarlo con el nombre del archivo de salida. guardamos en W_LINE la subcadena empezando con el valor del OFFSET y tomando el valor de W_SIZE en cantidad de caracteres. llamamos al método SAVE para crear el archivo ZIP con el archivo de entrada. Con el módulo de funciones SCMS_BINARY_TO_XSTRING convertimos el contenido del archivo de Binario a Hexadecimal. Creamos el objeto CL_ZIP y llamamos al método ADD para agregar el archivo de entrada al nuevo ZIP.

EXIT. FILE_IN = <FS_FILETAB>. ENDIF. IF FILE_IN IS INITIAL. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. W_FILE_IN = FILE_IN. DEFAULT_FILENAME = '*. REFRESH T_FILETAB. CLEAR T_FILETAB.*' FILE_FILTER = '*. 452 . Llamamos al método FILE_OPEN_DIALOG para poder almacenar la ruta del archivo de entrada.*' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC.

CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. CALL SCREEN 0100. 453 . Este es el código. TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. yo lo he utilizado para proyectos personales y no de trabajo.Crear un Control de Texto Este programa es bastante útil y necesario aunque que quizás no lo utilicen mucho. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. En lo personal. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. *=====================================================* * DECLARACION DE CONSTANTES * *=====================================================* CONSTANTS: LINE_LENGTH TYPE I VALUE 254.

LEAVE SCREEN. SET TITLEBAR '100'. SET PF-STATUS '100'. PERFORM CALL_EDITOR. OK_CODE = SY-UCOMM.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. " USER_COMMAND_0100 INPUT 454 . SET SCREEN 0. CLEAR SY-UCOMM. ENDCASE. CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. ENDMODULE. ENDMODULE.

CREATE OBJECT CUSTOM_CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 LIFETIME_DYNPRO_DYNPRO_LINK = 5. IF TEXT_EDITOR IS INITIAL. 455 .*&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR . ENDIF. CREATE OBJECT TEXT_EDITOR EXPORTING WORDWRAP_MODE = CL_GUI_TEXTEDIT=>WORDWRAP_AT_FIXED_POSITION WORDWRAP_POSITION = LINE_LENGTH WORDWRAP_TO_LINEBREAK_MODE = CL_GUI_TEXTEDIT=>TRUE PARENT = CUSTOM_CONTAINER EXCEPTIONS ERROR_CNTL_CREATE = 1 ERROR_CNTL_INIT = 2 ERROR_CNTL_LINK = 3 ERROR_DP_CREATE = 4 GUI_TYPE_NOT_SUPPORTED = 5 OTHERS = 6.

La variable OK_CODE almacena el código de función. ENDFORM. Esto determina cada cuantos caracteres debería hacer un salto de línea automático. TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. *=====================================================* * DECLARACION DE CONSTANTES * *=====================================================* CONSTANTS: LINE_LENGTH TYPE I VALUE 254. CUSTOM_CONTAINER es un objeto que creará el contenedor para nuestro control de texto. Declaramos una constante llamada LINE_LENGTH de tipo I con el valor 254. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: OK_CODE TYPE SY-UCOMM. " CALL_EDITOR Revisemos el código paso a paso. TEXT_EDITOR hace referencia al objeto que crea el control de texto. CALL METHOD CL_GUI_CFW=>FLUSH. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. 456 .

IF TEXT_EDITOR IS INITIAL. Llamamos a la pantalla 100 del Dynpro. " STATUS_0100 OUTPUT Asignamos el menú y el título del programa. PERFORM CALL_EDITOR.*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. CALL SCREEN 0100. En donde llamamos al control de texto. CREATE OBJECT CUSTOM_CONTAINER 457 . SET TITLEBAR '100'. SET PF-STATUS '100'. ENDMODULE. Llamamos al FORM CALL_EDITOR. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. *&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR .

CREATE OBJECT TEXT_EDITOR EXPORTING WORDWRAP_MODE = CL_GUI_TEXTEDIT=>WORDWRAP_AT_FIXED_POSITION WORDWRAP_POSITION = LINE_LENGTH WORDWRAP_TO_LINEBREAK_MODE = CL_GUI_TEXTEDIT=>TRUE PARENT = CUSTOM_CONTAINER EXCEPTIONS ERROR_CNTL_CREATE = 1 ERROR_CNTL_INIT = 2 ERROR_CNTL_LINK = 3 ERROR_DP_CREATE = 4 GUI_TYPE_NOT_SUPPORTED = 5 OTHERS = 6. " CALL_EDITOR Creamos el contenedor para el control de texto CUSTOM_CONTAINER. Creamos el objeto TEXT_EDITOR. ENDFORM. 458 . CALL METHOD CL_GUI_CFW=>FLUSH. ENDIF. EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS CNTL_ERROR = 1 CNTL_SYSTEM_ERROR = 2 CREATE_ERROR = 3 LIFETIME_ERROR = 4 LIFETIME_DYNPRO_DYNPRO_LINK = 5.

Lo cual significa que podemos cargar cualquier archivo. modificarlo y guardarlo. Como podemos ver.Limpiamos los controles con el método FLUSH. 459 . contamos con dos botones Load Local File (Cargar archivo local) y Save as Local File (Grabar como archivo local) .

WebDynpro

Introducción

El WebDynpro es la nueva forma de desarrollar aplicaciones en
NetWeaver, esto es porque está completamente orientado a web y
respeta el modelo MVC (Model View Controller – Modelo Vista
Controlador).
Aunque el Dynpro no está aún muy difundido, es una herramienta muy
potente y bastante sencilla de usar.

Creando nuestro primer WebDynpro

El WebDynpro, para mi gran tristeza no cuenta con una transacción
propia, sino se desarrolla dentro del Object Navigator (Navegador de
Objetos), transacción SE80.

460

Elegimos de la lista Web Dynpro Comp. / Intf. (Componente o
Interface Web Dynpro).

Asignamos un nombre y presionamos el botón Display .

Aceptamos en la ventana que nos muestra el sistema.

461

Asignamos una descripción y aceptamos.

Creamos una vista, donde van a estar los componentes que muestran
la información.
Para esto, hacemos un clic derecho sobre ZDUMMY_DYPRO y
seleccionamos Create Æ View (Crear Æ Vista).

462

Asignamos un nombre y una descripción a nuestra vista.

En este momento, el servicio tiene que conectarse con el servidor,
así que debemos ingresar nuestro usuario y password.

463

Una vez logeados, tenemos acceso al editor de vistas del
WebDynpro.

Debemos ir a la pestaña Context (Contexto) del editor de vistas.

Debemos hacer clic derecho en Context y elegir Create Æ Node
(Crear Æ Nodo)

464

Al nodo lo llamamos ZLENG_NODE y como Dictionary
Structure (Estructura del Diccionario) le pasamos la vista
ZVLENGUAJES_PROG.

Presionamos el botón Add Attribute from Structure (Agregar

atributo desde estructura) .
Seleccionamos todos los campos.

465

Como parámetro de entrada para nuestro programa, vamos a tener
un campo que represente el ID, así que creamos un Attribute
(Atributo) llamado ID_PROG.

466

Grabamos y regresamos a la pestaña Layout (Disposición).
Seleccionamos Standard Container (Contenedor Estándar) del
menú izquierdo y luego Group (Grupo).

En el panel derecho, seleccionamos Caption (Título) y cambiamos
el atributo Text (Texto).

467

Seleccionamos Create Container Form (Crear formulario
contenedor).

En la ventana que aparece a continuación, debemos presionar el

botón Context para poder asignar un valor a nuestro
contenedor.

468

Elegimos el nodo ID_PROG.

Seleccionamos el nodo ID_PROG_LABEL.

Y le asignamos el texto Id en la propiedad Text.

469

Finalmente, tendríamos esto.

Si queremos probar como va quedando nuestro programa, debemos
hacer lo siguiente.
Seleccionamos ZDUMMY_DYNPRO con un doble clic.

Y arrastramos ZDUMMY_VIEW hacia ZDUMMY_DYNPRO.

470

Grabamos y al momento de activar veremos una ventana como esta. 471 .

Una vez que todo se ha activado. En la siguiente pantalla. debemos crear una WebDynpro Application (Aplicación WebDynpro).Seleccionamos todos y aceptamos. solamente debemos grabar y activar. 472 . Asignamos un nombre y una descripción y aceptamos.

Para esto.Presionamos el botón Test/Execute (Probar/Ejecutar) o presionamos F8. presionamos el botón Log On . El navegador nos muestra una pantalla de login. así que debemos logearnos. 473 .

Como podemos ver. nuestro parámetro de entrada aparece perfectamente en el browser de internet. no va a pasar nada. el campo ID_PROG no tiene una ayúda de búsqueda asociada. 474 . por lo cual por mucho que presionemos F4. En este caso. Cerremos el browser y retornemos a nuestro programa.

475 . pestaña Layout. Le asignamos un título y hacemos clic derecho sobre el nodo TABLE para seleccionar Create Binding (Crear Atadura).Regresamos a la vista ZDUMMY_VIEW. Elegimos el componente Table (Tabla) de la pestaña Standard Complex (Complejos Estándar).

Asignamos textos a las cabeceras y tendremos algo como esto.Escogemos el Context ZLENG_NODE y dejamos todos los registro seleccionados y continuamos. 476 .

el cual tendrá el texto “Mostrar!”. 477 .Regresamos a la pestaña Standard Simple y seleccionamos el control Button (Botón).

Nos vamos a la pestaña Actions (Acciones) y veremos nuestra acción. por lo cual presionamos el botón OnAction. Asignamos el nombre SHOW y una descripción breve.Debemos asignar una acción al botón. 478 .

DATA: ID_PROG TYPE STRING. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG EQ ID_PROG. WD_CONTEXT->GET_ATTRIBUTE( exporting NAME = 'ID_PROG' importing VALUE = ID_PROG ). NODE_LENG = 479 . METHOD ONACTIONSHOW. ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG.Debemos presionar el botón ABAP Routine (Rutina ABAP) para poder asignar el código a nuestra acción.

ID_PROG es una variable de tipo String. esta es una interface que controla los nodos asociados a nuestro programa. NODE_LENG->BIND_TABLE( ITAB_LENG ). ITAB_LENG es una tabla interna que hace referencia a la vista ZVLENGUAJES_PROG. NODE_LENG->BIND_TABLE( ITAB_LENG ). ENDMETHOD. 480 . es decir. Declaramos la variable NODE_LENG que hace referencia a IF_WD_CONTEXT_NODE. Con GET_CHILD_NODE obtenemos el contexto del nodo que estamos utilizando y con BIND_TABLE enviamos los datos de la tabla hacia nuestro table control. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). de nuestro parámetro de entrada. WD_CONTEXT->GET_ATTRIBUTE( exporting NAME = 'ID_PROG' importing VALUE = ID_PROG ). Seleccionamos el registro de la vista ZVLENGUAJES_PROG siempre y cuando cumpla con el parámetro ID_PROG. Obtenemos el valor de atributo ID_PROG. WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ).

ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. NODE_LENG->BIND_TABLE( ITAB_LENG ). APPEND INITIAL LINE TO ITAB_LENG. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). 481 . Debemos ir a la pestaña Methods (Métodos) y seleccionar WDDOINIT que es una acción que se lanza cuando se ejecuta el programa por primera vez. es que agregamos una línea de cabecera a nuestra tabla interna. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE. Lo más resaltante de este código.Hay algo más que debemos hacer y que es muy importante. endmethod. para que el Table Control tenga algo que mostrar cuando lanzemos el programa. method WDDOINIT.

Así que vamos a agregar otra caja de texto para poder crear un rango de búsqueda..Todo se ve muy bien. 482 .. pero estamos limitados a buscar solamente un valor.

El nuevo atributo se llamará ID_PROG_FIN. 483 . Renombramos el atributo ID_PROG a ID_PROG_INI. llamado PARAMETROS que no contendrá referencia a ningún tabla. Ahora. puesto que ahora vamos a tener dos atributos distintos. creamos un nuevo nodo.Regresamos a la pestaña Context. Solamente nos servirá como contenedor para los atributos.

484 .Lo que hacemos es arrastrar los atributos a nuestro nodo PARAMETROS.

Regresamos al Layout y eliminamos el campo de texto ID_PROG. con dos parámetros de entrada. Creamos un nuevo Container Form. que nos servirán para definir nuestro rango. Nuestro diseño quedará como se muestra a continuación. 485 .

DATA: ID_PROG_INI TYPE STRING. DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE. METHOD ONACTIONSHOW. 486 .Regresamos a la pestaña Actions y al código del método Show. FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG. ID_PROG_FIN TYPE STRING. ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'PARAMETROS' ).

ENDMETHOD. APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). DATA: ID_PROG_INI TYPE STRING. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG IN ID_PROG. Veamos un poco el código. WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ). <FS_IDPROG>-OPTION = 'BT'. <FS_IDPROG>-LOW = ID_PROG_INI. <FS_IDPROG>-SIGN = 'I'. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). <FS_IDPROG>-HIGH = ID_PROG_FIN. NODE_LENG->BIND_TABLE( ITAB_LENG ). 487 . ID_PROG_FIN TYPE STRING.

Declaramos dos variables. <FS_IDPROG>-OPTION = 'BT'. cada cual almacenará el valor de su parámetro correspondiente. ID_PROG_INI e ID_PROG_FIN. Asignamos el nodo PARAMETROS a nuestra variable NODE_LENG. Declaramos la variable ID_PROG de tipo RANGE (Rango). FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG. APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. Recuperamos los valores de ambos parámetros. 488 . NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ). Declaramos un Field-Symbol. con lo cual podremos definir un rango de valores para seleccionar de la vista. <FS_IDPROG>-SIGN = 'I'. NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'PARAMETROS' ).

En el select. reemplazamos el EQ por un IN. <FS_IDPROG>-HIGH = ID_PROG_FIN. y asignamos los valores correspondientes. 489 . <FS_IDPROG>-LOW = ID_PROG_INI. LOW es el valor inicial y HIGH es el valor final. donde BT Æ Between (Entre) y EQ Æ Equal (Igual). con lo cual podemos utilizar el rango para pasar más de un valor como parámetro. OPTION es el tipo de correspondencia entre los datos. Agregamos una línea de cabecera a nuestro rango. SIGN es el tipo de valor. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG IN ID_PROG.

490 .

así que nuevamente debemos ir a la transacción SE80 y escoger BSP Application (Aplicación BSP) en el menú. es decir. JSP o PHP. 491 . El BSP es anterior al WebDynpro. el BSP no tiene una transacción propia (Otra queja más para SAP). Creando nuestro primer BSP Al igual que en el caso del WebDynpro. viene a ser un lenguaje script basado en ABAP.BSP Introducción El BSP (Business Server Pages – Página del Servidor de Aplicaciones). lo que no se puede hacer con WebDynpro. por el contrario. se hace con BSP. aunque esto no quiere decir que sea obsoleto o menos completo. una especio de ASP.

Creamos nuestra aplicación ZDUMMY_BSP. 492 .bsp haciendo clic derecho Create Æ Page (Crear Æ Página). Creamos una página llamada index.

En la pestaña Layout (Disposición) colocamos el siguiente código. En este caso. 493 . <%@page language="abap"%> <html> <head> </head> <body> <form method="post"> Id <input type="text" name="ID_PROG" value=""> <input type="submit" name="onInputProcessing(show)" value="Enviar!"> </form> <!--navigation->set_parameter( 'ID_PROG' )--> </body> </html> Como podemos ver esta página. nos es más que HTML con un par de características adicionales. onInputProcessing(show) Æ Evento llamado cuando se ejecuta una acción de procesamiento de datos. show representa a nuestro FORM. navigation->set_parameter( ‘ID_PROG’ ) ÆIndica que estamos estableciendo el campo ID_PROG como un parámetro de salida de nuestra página. Creamos una nueva página.

select ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG EQ W_ID_PROG. %> <table border=”1”> <tr> <b><td>Id</td><td>Nombre</td> <td>Lenguaje</td><td>Entorno</td></b> </tr> <% loop at t_leng assigning <fs_leng>. t_leng type standard table of ZVLENGUAJES_PROG. %> 494 . <%@page language="abap"%> <html> <body> <% data: w_id_prog type zvlenguajes_prog-id_prog. field-symbols: <fs_leng> like line of t_leng. w_id_prog = request->get_form_field( 'ID_PROG' ).Este es el código de la página.

495 .bsp nos vamos a la pestaña Event Handler (Manejador de Eventos) y escogemos del menú OnInputProcessing. seleccionamos datos y los mostramos en una tabla. dentro de los tags <% y %>.<tr> <td><%= <fs_leng>-ID_PROG %></td> <td><%= <fs_leng>-NOM_PROG %></td> <td><%= <fs_leng>-LENGUAJE %></td> <td><%= <fs_leng>-ENTORNO %></td> </tr> <% endloop. Además hemos llamado variables utilizando los tags <%= y %>. En la página index. en esta página hemos incluido código ABAP. Esto es porque el BSP es un lenguaje script y se integra perfectamente con el HTML.bsp. estas dos páginas no se comunican entre sí. Hasta ahora. así que vamos a agregar algo de código para conectarlas. Simplemente recibimos un parámetro de la página index. %> </table> </body> </html> Como podemos ver.

EVENT_ID es una variable que almacena los “códigos de función” de las páginas. Nos vamos a la aplicación con un doble clic.bsp. CASE EVENT_ID. NAVIGATION->NEXT_PAGE('SHOW_DATA'). WHEN 'show'.Agregamos el siguiente código. Si llamamos a nuestro FORM de la página index. ENDCASE. establecemos el parámetro ID_PROG y llamamos a la página SHOW_DATA (Cabe destacar que este es un alias que definiremos en unos momentos). 496 . NAVIGATION->SET_PARAMETER('ID_PROG').

497 . establecemos la página principal en la pestaña Properties (Propiedades).bsp llama al alias SHOW_DATA que representa a la página Show_Data. Debemos ingresar nuestro Usuario y Password para poder iniciar el servidor. activamos y ejecutamos. presionando el botón Test (Probar) o presionando F8.Establecemos que index.bsp Finalmente. Grabamos.

498 .

dos parámetros ID_PROG_INI y ID_PROG_FIN. es crear un rango de valores para poder hacer una mejor selección en el programa. 499 . al igual que con el WebDynpro. Vamos a la pestaña Event Handler y al evento OnInputProcessing.bsp y modificamos ligeramente el código. podemos hacer lo que queramos con el formato de salida de la tabla. <%@page language="abap"%> <html> <head> </head> <body> <form method="post"> Id desde <input type="text" name="ID_PROG_INI" value=""> Id hasta <input type="text" name="ID_PROG_FIN" value=""> <input type="submit" name="onInputProcessing(show)" value="Enviar!"> </form> <!--navigation->set_parameter( 'ID_PROG_INI' )--> <!--navigation->set_parameter( 'ID_PROG_FIN' )--> </body> </html> Tenemos ahora. pero lo que vamos a hacer.Al ser HTML. Regresamos a la página index.

500 . <fs_r_leng>-LOW = W_ID_PROG_INI. t_leng type standard table of ZVLENGUAJES_PROG. r_leng type range of ZVLENGUAJES_PROG-ID_PROG. <fs_r_leng>-OPTION = 'BT'. NAVIGATION->NEXT_PAGE('SHOW_DATA'). w_id_prog_fin = request->get_form_field( 'ID_PROG_FIN' ). w_id_prog_ini = request->get_form_field( 'ID_PROG_INI' ).bsp hacemos un pequeños cambios. <fs_r_leng>-HIGH = W_ID_PROG_FIN. <%@page language="abap" %> <html> <body> <% data: w_id_prog_ini type zvlenguajes_prog-id_prog. <fs_r_leng>-SIGN = 'I'. NAVIGATION->SET_PARAMETER('ID_PROG_INI'). WHEN 'show'. append initial line to r_leng assigning <fs_r_leng>. field-symbols: <fs_leng> like line of t_leng.bsp En la pagína Show_Data.CASE EVENT_ID. w_id_prog_fin type zvlenguajes_prog-id_prog. Enviamos ambos parámetros a la página Show_Data. <fs_r_leng> like line of r_leng. ENDCASE. NAVIGATION->SET_PARAMETER('ID_PROG_FIN').

%> <table border="1"> <tr> <b><td>Id</td><td>Nombre</td> <td>Lenguaje</td><td>Entorno</td></b> </tr> <% loop at t_leng assigning <fs_leng>. 501 . select ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG in r_leng. asignamos los parámetros de entrada W_ID_PROG_INI y W_ID_PROG_FIN al rango y lo utilizamos para nuestro select. %> </table> </body> </html> Creamos un rango R_LENG. un field-Symbol <FS_R_LENG>. %> <tr> <td><%= <fs_leng>-ID_PROG %></td> <td><%= <fs_leng>-NOM_PROG %></td> <td><%= <fs_leng>-LENGUAJE %></td> <td><%= <fs_leng>-ENTORNO %></td> </tr> <% endloop.

502 .

T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. END OF TY_TAB. T_FILETAB TYPE FILETABLE. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_TAB. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. el ABAP nos permite trabajar con archivos XML de una manera bastante simple. 503 . LINE(100) TYPE C. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. puesto que es sumamente flexible.ABAP y XML El XML (Extensible Markup Language – Lenguaje extensible de marcas) es un formato de intercambio de archivos muy utilizado en al actualidad. Como era de esperarse.

W_SUBRC TYPE SY-SUBRC. PARAMETERS: FILE LIKE RLGRAP-FILENAME. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. SELECTION-SCREEN END OF BLOCK TEST.xml' 504 . CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION.*=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: XML_OUT TYPE STRING. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PERFORM DESCARGAR_XML. W_FILE TYPE STRING. SIZE TYPE I. PERFORM OBTENER_DATOS. PERFORM GENERAR_XML.

SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. *&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. W_FILE = FILE. CALL TRANSFORMATION ('ID') 505 . ENDIF. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>.xml' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC. " OBTENER_DATOS *&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. FILE_FILTER = '*. EXIT. ELSE. FILE = <FS_FILETAB>. IF FILE IS INITIAL. ENDFORM.

ENDFORM. ENDFORM. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME = W_FILE FILETYPE = 'BIN' CHANGING DATA_TAB = T_TAB. SOURCE TAB = T_ZLENG[] RESULT XML XML_OUT. 506 . " DESCARGAR_XML Revisemos el código fuente. " GENERAR_XML *&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. CALL FUNCTION 'SWA_STRING_TO_TABLE' EXPORTING CHARACTER_STRING = XML_OUT IMPORTING CHARACTER_TABLE = T_TAB.

T_FILETAB TYPE FILETABLE.*=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_TAB. 507 . LINE(100) TYPE C. una para guardar el XML. T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. Declaramos un field-symbol. Creamos algunas tablas internas. otra para guardar los datos de la Base de Datos y el último para guardar la ruta del archivo de salida. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. END OF TY_TAB. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. Declaramos un TYPE que contiene un solo campo llamado LINE de 100 de longitud y tipo C.

SIZE TYPE I. W_FILE TYPE STRING. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. Declaramos un parámetro de entrada para poder obtener la ruta donde se generará el archivo XML. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PERFORM OBTENER_DATOS. SELECTION-SCREEN END OF BLOCK TEST. PERFORM GENERAR_XML.*=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: XML_OUT TYPE STRING. PERFORM DESCARGAR_XML. XML_OUT es una cadena que contendrá la información para generar el XML. PARAMETERS: FILE LIKE RLGRAP-FILENAME. W_SUBRC TYPE SY-SUBRC. 508 .

IF FILE IS INITIAL. EXIT. Obtenemos la ruta del archivo a descargar. W_FILE = FILE.xml' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC.OBTENER_DATOS nos sirve para seleccionar los datos de la vista. ENDIF. DESCARGAR_XML guarda el archivo en la ruta especificada. 509 . GENERAR_XML crea el archivo XML. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*.xml' FILE_FILTER = '*. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. ELSE.

ENDFORM. *&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. ENDFORM.*&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. CALL TRANSFORMATION ('ID') SOURCE TAB = T_ZLENG[] RESULT XML XML_OUT. 510 . SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. " OBTENER_DATOS Seleccionamos los registros de la vista. " GENERAR_XML CALL TRANSFORMATION nos sirve para llamar a una transformación que se encarga de convertir los datos de la tabla inerna en un cadena XML.

ENDFORM. " DESCARGAR_XML SWA_STRING_TO_TABLE nos sirve para convertir la cadena XML_OUT a una tabla con los datos del XML.*&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. El método GUI_DOWNLOAD nos permite descargar el archivo XML. 511 . CALL FUNCTION 'SWA_STRING_TO_TABLE' EXPORTING CHARACTER_STRING = XML_OUT IMPORTING CHARACTER_TABLE = T_TAB. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME = W_FILE FILETYPE = 'BIN' CHANGING DATA_TAB = T_TAB.

El código es practicamente el mismo. solo cambia el orden. END OF TY_TAB. veamos como hacer lo contrario. generemos una tabla interna en base a un archivo XML. LINE(100) TYPE C. *=====================================================* * DECLARACION DE TYPES * *=====================================================* TYPES: BEGIN OF TY_TAB. 512 . es decir.Ahora que ya vimos como podemos generar un archivo XML a partir de una tabla interna.

PARAMETERS: FILE LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST. SIZE TYPE I. <FS_ZLENG> LIKE LINE OF T_ZLENG. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB.*=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. W_SUBRC TYPE SY-SUBRC. 513 . T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. T_FILETAB TYPE FILETABLE. *=====================================================* * DECLARACION DE VARIABLES * *=====================================================* DATA: XML_OUT TYPE STRING. W_FILE TYPE STRING.

PERFORM IMPRIMIR. FILE = <FS_FILETAB>. ENDIF. W_FILE = FILE. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE.xml' FILE_FILTER = '*. IF FILE IS INITIAL. PERFORM GENERAR_TABLA_INTERNA. EXIT. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*.xml' CHANGING FILE_TABLE = T_FILETAB RC = W_SUBRC.*=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. ELSE. 514 . PERFORM CARGAR_XML.

ENDFORM. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME = W_FILE FILETYPE = 'BIN' CHANGING DATA_TAB = T_TAB. " CARGAR_XML 515 . " GENERAR_TABLA_INTERNA *&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[].*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. CALL FUNCTION 'SWA_STRING_FROM_TABLE' EXPORTING CHARACTER_TABLE = T_TAB IMPORTING CHARACTER_STRING = XML_OUT. ENDFORM.

<FS_ZLENG>-ENTORNO. WRITE:/ <FS_ZLENG>-ID_PROG. lo transforma en una cadena XML. LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. GENERAR_TABLA_INTERNA transforma la cadena XML en una tabla interna. (Con formato XML claro está). " IMPRIMIR Revisemos el código. pero solamente las partes que han cambiado. ENDFORM. <FS_ZLENG>-NOM_PROG. Luego. PERFORM CARGAR_XML. <FS_ZLENG>-LENGUAJE. IMPRIMIR muestra el resultado en pantalla. PERFORM IMPRIMIR.*&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. *=====================================================* * START-OF-SELECTION * *=====================================================* START-OF-SELECTION. PERFORM GENERAR_TABLA_INTERNA. CARGAR_XML carga el archivo y lo guarda en un tabla interna. 516 . ENDLOOP.

*&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. " CARGAR_XML Utilizamos el método GUI_UPLOAD para cargar el archivo XML. ENDFORM. CALL FUNCTION 'SWA_STRING_FROM_TABLE' EXPORTING CHARACTER_TABLE = T_TAB IMPORTING CHARACTER_STRING = XML_OUT. 517 . Con el módulo de funciones SWA_STRING_FROM_TABLE convertimos la tabla interna en una cadena XML. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME = W_FILE FILETYPE = 'BIN' CHANGING DATA_TAB = T_TAB.

CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[]. 518 .*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. ENDFORM. WRITE:/ <FS_ZLENG>-ID_PROG. <FS_ZLENG>-NOM_PROG. <FS_ZLENG>-LENGUAJE. *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. es bastante sencillo trabajar con XML y ABAP. <FS_ZLENG>-ENTORNO. ENDFORM. LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. Como pueden ver. " GENERAR_TABLA_INTERNA Utilizamos el CALL TRANSFORMATION para recibir una cadena XML y retornar una tabla interna. ENDLOOP. " IMPRIMIR Imprimimos el contenido de la tabla interna.

519 .

lo cual lo hace excelente para aquellas personas que nunca han hecho una integración con NetWeaver.Scripting in a Box Scripting in a Box es una herramienta creada por Craig Cmehil de SAP AG. el Scripting in a Box simplementese descarga y se configura. Veamos algunas imagenes de Scripting a in Box. como PHP. al igual que el Eclipse. debemos ingresar a la siguiente dirección (Debemos ser usuarios del SDN – SAP Developer Network). Como era de suponerse. puesto que no existe una instalación. Esta herramienta basada en Eclipse. esta herramienta es indispensable para el trabajo con lenguajes script.com/irj/sdn/go/portal/prtroot/docs/library/uuid/e5 0bd86e-0a01-0010-53bd-857585234a6a O. 520 . reune a todos los lenguajes script que pueden conectados con NetWeaver. Para descargarlo. La instalación es lo mejor de todo. Rails. ingresar a http://sdn. Perl y Python.sdn.com Æ Downloads Æ More Downloadable Tools for Developers Æ Scripting in a Box. https://www.sap.sap. Ruby. cuenta además con varios ejemplos (Incluyendo mi emulador de SE16 en PHP). De muy sencilla instalación.

521 .

522 .

podemos almacenar Programas. no hay hasta el momento ninguna que pueda competir con SAPLink.google. desarrollada en ABAP. Creando paquetes basados en código XML. 523 . opción de descargar Plug-Ins y un constante monitoreo de los posibles errores. nos permite crear una verdadera librería de códigos para poder transportar o compartir con los demás. Esta herramienta. Dynpros. Si bien existen muchas herramientas para descargar y cargar elementos de NetWeaver (Yo he creado varias de ellas).com/p/saplink/wiki/pluginList Veamos algunas cuantas imágenes. SmartForms y un largo etcétera.SAPLink SAPLink es una herramienta creada por Daniel McWeeney y Ed Herrmann de Colgate .com/p/saplink/ Y para los Plug-Ins. WebDynpros. puesto que SAPLink nos brinda una interfaz muy sencilla.google. http://code. Podemos descargarla. http://code.Palmolive. debemos ingresar a la siguiente dirección. deberemos ingresar a la dirección.

524 .

525 .

526 .

por lo cual.4 Æ http://saprfc. Si se preguntan porque utilizar PHP con NetWeaver. En todo caso.1.2 Æ http://www. fácil de aprender y configurar”. es un lenguaje orientado a objetos.0. para obtener datos de tablas.apache. ejecutar funciones.55 Æ http://httpd.php. Su sintaxis es bastante similar a la de C++. se conecten con NetWeaver.Integración PHP-NetWeaver Introducción El PHP (PHP Preprocessor). es open source y en su versión 5 en adelante. hacer lo mismo que hacemos todos los días.org • SAPRFC 1. Lo único que necesitamos para poder integrar PHP con NetWeaver es lo siguiente (Si no hemos instalado Scripting in a Box claro está): • PHP versión 5. BAPI’s. que nos permite que las páginas web que desarrollemos en PHP. la respuesta es muy simple: “PHP es gratuito. ya depende de cada uno que tecnología utilizar. Lleva varios años en el mercado.net • Apache WebServer versión 2.4-5.sourceforge. etc.net/ • NetWeaver Sneak Preview o SAP NetWeaver o MiniSAP o MiniWas. conociendo C++ o Java. es un lenguaje de programación para páginas web dinámicas. 527 . existe un conector llamado SAPRFC.0. Es decir. Gracias a Eduard Koucky. es muy fácil de aprender. pero accediendo a través de una interface web. en vez de utilizar WebDynpro o BSP.

<?php phpinfo(). simplemente llamamos a una página con el comando PHP_INFO(). no vamos a enseñar a instalar el PHP o el Apache. ni tampoco a programar en PHP. dentro de la carpeta /ext del PHP. lo que vamos a hacer es configurar el SAPRFC e integrarlo con NetWeaver. Instalando el SAPRFC Simplemente debemos descomprimir el archivo .ZIP y copiar el archivo php_saprfc.dll. Para comprobar que todo está funcionando correctamente.ini debemos agregar la siguiente línea. Reiniciamos el servicio del Apache y estamos listos para comenzar.Como este es un libro sobre NetWeaver y no sobre PHP (Para eso está.dll. extension = php_saprfc. En el PHP. ?> 528 . El Arte de Programar PHP).

PRINT("<FORM ACTION='index. un emulador de SE16. PRINT("<BR><TABLE BORDER='1' BORDERCOLOR='BLUE' BGCOLOR='WHITE'>"). PRINT("<TR><TD>Server</TD><TD><INPUT TYPE='TEXT' NAME='Server'></TD></TR>"). es crear nuestra clase para poder logearnos a NetWeaver. function Login_Page() { PRINT("<DIV ALIGN='CENTER'><BR><BR><BR><BR><H1>PHP & SAP . $rfc.SE16 Emulator</H1>"). PRINT("<TR><TD>Client</TD><TD><INPUT TYPE='TEXT' 529 . Lo primero que debemos hacer. PRINT("<TR><TD>System Number</TD><TD><INPUT TYPE='TEXT' NAME='Sysnum' SIZE='3'></TD></TR>").php <?php Class Login { var $Login. La llamamos Login_Class. es lo primero que hice yo con PHP y NetWeaver).Estableciendo la comunicación con NetWeaver Vamos a crear un ejemplo simple (En realidad.php' METHOD='POST'>").

"PASSWD"=>$Pass.$Sysnum. PRINT("</FORM>"). "USER"=>$User. } function Log_In($Server. IF ( !$this->rfc ) { ECHO "The connection fails with the following 530 . PRINT("<TR><TD>Password</TD><TD><INPUT TYPE='PASSWORD' NAME='Pass'></TD></TR>"). PRINT("<INPUT TYPE='RESET' value='Clear'></TD></TR>").$Client. "SYSNR"=>$Sysnum.$User. PRINT("<TR><TD COLSPAN='2' ALIGN='CENTER'><INPUT TYPE='SUBMIT' value='Log In' NAME='LOG_IN'>"). return $this->Login.NAME='Client' SIZE='3'></TD></TR>"). } function RFC_Connection($Login) { $this->rfc = saprfc_open($Login). PRINT("</DIV>").$Pass) { $this->Login = array ("ASHOST"=>$Server. PRINT("<TR><TD>User</TD><TD><INPUT TYPE='TEXT' NAME='User'></TD></TR>"). PRINT("<TABLE>"). "CLIENT"=>$Client. "CODEPAGE"=>"1404").

php que es la que va hacer todo el trabajo “sucio”. RFC_Connection Æ Reestablecemos la conexión. <?php Class SE16 { var $fce. Ahora. Log_In Æ Nos conectamos a NetWeaver con los parámetros ingresados. EXIT. Número de Sistema y Cliente. } } } ?> Lo que hacemos es crear algunas funciones. donde debemos ingresar el Usuario. } else { return $this->rfc.saprfc_error(). Password. Servidor. 531 . debemos crear la clase SE16. error:". Login_Page Æ Nos muestra la pantalla de logeo.

"/")."DATA").".$RFC_Me) { $this->fce = saprfc_function_discover($RFC_Me. saprfc_import ($this->fce."QUERY_TABLE"."OPTIONS").function Show_Table($Table. saprfc_table_init ($this->fce. $rfc_rc = "". saprfc_table_init ($this->fce. exit. IF (! $this->fce ) { ECHO "The function module had failed. saprfc_import ($this->fce.saprfc_exception ($this->fce)). saprfc_table_init ($this->fce.$Table)."DELIMITER". EXIT. if ($rfc_rc != SAPRFC_OK) { if ($rfc == SAPRFC_EXCEPTION ) echo ("Exception raised: ". } 532 . "RFC_READ_TABLE")."FIELDS"). $rfc_rc = saprfc_call_and_receive ($this->fce).saprfc_error ($this->fce)). else echo ("Call error: ". } $Table = STRTOUPPER($Table).

ECHO "</TD>". } ECHO "</TR>".$i).$data_row = saprfc_table_rows ($this->fce. if($rem == 0) { ECHO "<TR BGCOLOR='#ADDEF7'>". ECHO "<TR>". $i<=$field_row . for($i=1. } 533 ."FIELDS"). $rem = $i % 2. $i<=$data_row.$DATA['WA']). ECHO "<BR>". ECHO "<TABLE BORDER='1' BORDERCOLOR='BLUE'>"."DATA"). } else { ECHO "<TR BGCOLOR='#FFFFFF'>". $Table. ECHO "<BR><BR>". ECHO "<TD BGCOLOR='#4D80F6'>".$i). ECHO $FIELDS['FIELDNAME']."DATA". for ($i=1. $field_row = saprfc_table_rows ($this->fce. ECHO "Table: " . $TEST = SPLIT("/". $i++) { $FIELDS = saprfc_table_read ($this->fce."FIELDS". $i++) { $DATA = saprfc_table_read ($this->fce.

&nbsp. PRINT("<INPUT TYPE='HIDDEN' NAME='LOG_IN'><BR>"). $j<$field_row.&nbsp. ECHO $TEST[$j]."). } ECHO "</TR>". 534 . PRINT("</FORM>"). for($j=0. } ECHO "</TABLE>". PRINT("<INPUT TYPE='SUBMIT' value='Back' NAME='Back'>&nbs p. $fce = saprfc_function_discover($rfc. obtiene los datos y los muestra utilizando un formato de tabla de HTML. Vamos a analizar algunos puntos clave del código. ECHO "</CENTER>". ECHO "<CENTER>". ECHO "</TD>". Show_Table. } } ?> Aquí tenemos una sola función. PRINT("<FORM ACTION='index.php' METHOD='POST'>").”RFC_READ_TABLE”). $j++) { ECHO "<TD>". esta función recibe el nombre de la tabla que queremos visualizar. se conecta con el módulo de funciones RFC_READ_TABLE.

Leemos el registro de la tabla por medio de un índice. Inicializamos la tabla interna $rc = saprfc_call_and_recieve($fce). $DATA = saprfc_table_read($fce. saprfc_import($fce. Imprimimos el contenido de la tabla especificando el campo.”DATA”.Verificamos que el módulo de funciones exista. Ejecutamos la función y recibimos los parámetros IMPORT o tablas internas de salida. Asignamos el nombre la tabla al parámetro QUERY_TABLE. Leemos la cantidad de líneas que tiene la tabla interna.”DATA”).”\n”).”QUERY_TABLE”.$i).$Table). saprfc_table_init($fce. $data_row = saprfc_table_rows($fce.”OPTIONS”). echo($DATA[WA]. 535 .

} </style> </head> <body> <?php if(isset($_POST['LOG_IN']) || (isset($_POST['Table']))) 536 . saprfc_close($fce).php <?php session_start(). ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF.saprfc_function_free($fce). Liberamos la función de la memoria. es obviamente index. Cerramos la conexión con SAP. podemos continuar con las páginas PHP. include("Login_Class.border: 1px solid #C7D3EA. La primera.} #login {background: #E5EAF6.text-align: center. Ahora.php").

ECHO "<A HREF='index. $_SESSION["Client"] = $_POST["Client"]. PRINT("<FORM ACTION='Operation. ECHO "</CENTER>". PRINT("<INPUT TYPE='SUBMIT' value='Show Table' NAME='Show_Table'>&nbsp. } $Login = new Login(). PRINT("</FORM>"). PRINT("<INPUT TYPE='TEXT' NAME='Table'><BR>").$_SESSION["Pass"]). $RFC_Me = $Login->RFC_Connection($Log_Me).&nbsp. session_destroy(). ECHO "<CENTER>"."). } else { $_SESSION = array(). $Log_Me = $Login->Log_In ($_SESSION["Server"].&nbsp.$_SESSION["Sysnum"]. $_SESSION["Pass"] = $_POST["Pass"]. 537 . $_SESSION["Client"].php' METHOD='POST'>").{ if(!isset($_SESSION["Server"])) { $_SESSION["Server"] = $_POST["Server"].php'>Log Out</A>". $_SESSION["User"] = $_POST["User"]. $_SESSION["Sysnum"] = $_POST["Sysnum"]. $_SESSION["User"].

} </style> </head> <body> 538 . lo que hacemos es llamar a nuestra clase Login para poder conectarnos a NetWeaver y solicitar la tabla que queremos visualizar. include("Login_Class. La última página es Operation.border: 1px solid #C7D3EA.text-align: left.php").$Login = new Login(). } ?> </body> </html> En esta página.php en donde llamamos a la clase SE16 para mostrar los datos en la tabla. <?php session_start(). ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF.php"). include("SE16.} #login {background: #E5EAF6. $Login->Login_Page().

$SE16->Show_Table($Table. } ?> </body> </html> Con esto terminamos y podemos ver el programa en ejecución. $_SESSION["User"]. $Log_Me = $Login- >Log_In($_SESSION["Server"]. if(isset($_POST['Table'])) { $Table = $_POST['Table']. $RFC_Me = $Login->RFC_Connection($Log_Me).$_SESSION["Sysnum"]. 539 .$_SESSION["Pass"]).<?php $Login = new Login(). $_SESSION["Client"].$RFC_Me). $SE16 = new SE16().

540 .

19- mswin32..Y como dice “Matz”.gem Æ http://www.com/download/ruby/saprfc-0.piersharding. Lo único que necesitamos para poder integrar Ruby con NetWeaver es lo siguiente.php/12751/ruby185- 21.gem • SAPRFC.wi n32 541 . Como no podía ser de otra forma.org/frs/download. existe un conector para Ruby con NetWeaver. totalmente orientado a objetos y que hereda las características más importantes de Perl y Python.so. llamado SAP::Rfc creado por el genial Piers Harding.19-mswin32. creado hace más de 11 años por Yukihiro “Matz” Matsumoto.com/download/ruby/saprfc. • Ruby Versión 1..so. Ruby es un lenguaje de fácil aprendizaje.5 Æ http://rubyforge.Integración Ruby-NetWeaver Introducción Ruby es un lenguaje de programación japonés. agrega todo lo que falta a esos dos lenguajes.exe • SAPRFC-0.win32 Æ http://www.piersharding.8.

que es bastante poco. (Para aprender Ruby. Estableciendo la comunicación con NetWeaver La integración de Ruby con NetWeaver es bastante sencilla. Como este no es un libro sobre Ruby. Para comprobar la instalación basta con hacer un GEM LIST para obtener la lista. 542 . pueden comprar “El Arte de Programar Ruby”).gem y listo.Instalando el SAP::Rfc Simplemente debemos hacer un GEM INSTALL SAPRFC-0.19- mswin32. y un pequeño ejemplo (Emulador de SE16) nos tomará solamente 63 líneas. solamente vamos a revisar las líneas de código más importantes.

new(:ashost => $Host.chop!.chop!. "\n" # lookup the interface for RFC_READ_TABLE itab = rfc.to_i.is_connected().discover("RFC_READ_TABLE") print "\nEnter table: " 543 . :sysnr => $Sysnr. :user => $User.to_i. :passwd => $Password.chop!. :trace => 1) # test the connection # print "is_connected: ".chop!.require 'rubygems' gem 'saprfc' require "SAP/Rfc" print "Host: " $Host = gets print "System Number: " $Sysnr = gets print "Client: " $Client = gets print "User: " $User = gets print "Password: " $Password = gets rfc = SAP::Rfc. rfc.chop!. :lang => "EN". :client => $Client.

strip!) } $Data_Len = $Data..$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.chop! itab. rfc..strip.call(itab) $Fields = Array.new $Data = Array.close().query_table.$Fields_Len print $Data_Split[i].length itab..value = $Table.delimiter.fields.split("|") for i in 1..hashRows {|field| $Data.push(field) } $Fields_Len = $Fields. "|" end print "\n\n" end print "\nclose connection: ".new itab.new $Data_Fields = Array.new $Data_Split = Array.hashRows {|field| $Fields.value = "|" # do the RFC call rfc. "\n" print "Exit" 544 .data. $Table = gets print "\n" itab.to_s.push( field.to_s.length for i in 0.

rfc = SAP::Rfc.chop!. itab = rfc.query_table.delimiter.chop!. :lang => "EN".chop!.value = $Table. require ‘rubygems’ gem ‘saprfc’ require ‘SAP/Rfc’ Llamamos a la librería de SAP::Rfc y especificamos que queremos utilizar el GEM.Veamos un poco el código.to_i.value = "|" 545 . :user => $User. :trace => 1) Establecemos la conexión pasando los parámetros indicados por el usuario. itab.to_i.new(:ashost => $Host.chop!. :client => $Client. :sysnr => $Sysnr.discover("RFC_READ_TABLE") Verificamos que el módulo de funciones exista.chop!.chop! itab. :passwd => $Password.

hashRows {|field| $Fields. 546 ..call(itab) Ejecutamos la llamada al módulo de funciones.$Fields_Len print $Data_Split[i].to_s.length itab.to_s.push(field) } $Fields_Len = $Fields.split("|") for i in 1.strip!) } $Data_Len = $Data... Ahora.hashRows {|field| $Data.Llenamos los parámetros del módulo de funciones.$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.push(field.fields. for i in 0. itab.strip.data. rfc. "|" end print "\n\n" end Imprimimos el resultado en pantalla. podemos ver algunas imágenes.length Obtenemos los datos que nos retorna la función..

547 .

com/product.sap.0 (2004s) – ABAP Trial Version https://www. http://www. Podemos conseguirla de dos maneras.sap- press.sdn.sap.Donde conseguir el SAP NetWeaver Sneak Preview El SAP NetWeaver Sneak Preview es la versión para desarrolladores de SAP AG. • Comprando el libro ABAP Objects : ABAP Programming in SAP NetWeaver de Horst Keller y Sascha Krüger en SAP Press.cfm?account=&product=H1934 • Descargandolo desde el SDN (SAP Developer Network – http://sdn.com) en Download Æ SAP NetWeaver Main Releases Æ SAP NetWeaver 7.com/irj/sdn/go/portal/prtroot/docs/library/ uuid/80fd9a0a-e306-2a10-c896-b84c77c13ed2 548 .

lulu.com/product.com/content/561744 Hay muchas personas a quienes debo agredecer.cfm?account=&product=H1934 • Next Generation ABAP Development de Rich Heilman y Thomas Jung – SAP Press. mis agradecimientos..com/product. 549 . http://www.cfm?account=&product=H1986 • El Arte de Programar SAP R/3 de Alvaro Tejada Galindo – Lulu Press.Bibliografía y agradecimientos • ABAP Objects : ABAP Programming in SAP NetWeaver de Horst Keller y Sascha Krüger – SAP Press. • A Abesh Bathacharjee quien con su amistad y sentido del humor me ayudó a ser más creativo.sap- press. puesto que me han apoyado mucho al momento de estar escribiendo este libro. http://www. Sin orden de importancia.sap- press.. a quienes dedico este libro. http://www. • Mi esposa Milly y mi hija Tammy Luz. • A Thomas Jung y Rich Heilman (A quienes conocí en Las Vegas TechEd 2007 y gracias a ellos escribí este libro). • A Craig Cmehil que siempre ha sido un Mentor para mi. • A Cathy Welsh por facilitarme información valiosa sobre WebDynpro.

• Al SDN (SAP Developer Network) por haberme eligido como Mentor de SAP. • A Marilyn Pratt por haberme demostrado que “Las abuelitas también pueden rockear”. 550 . • A Mark Finnern por la confianza en mi que siempre ha demostrado.

com • BPX (Business Process Expert) Æ http://bpx.com • El Blog Tecnológico de Blag Æ http://atejada.sap4.com • SAP Marketplace Æ http://service.Enlaces Web Para terminar. • SDN (SAP Developer Network) Æ http://sdn.sap.com • Alvaro Tejada Galindo’s SDN Blogs Æ https://www.sap.sap.sap.sap.blogspot.com • SAP Help Æ http://help.com 551 . quiero agregar algunos enlaces web que pienso que pueden ser bastante útiles.sdn.sap.com/irj/sdn/weblogs?blog=/pub/u/4802 4 • SAP Æ http://www.com • SAP ABAP en castellano Æ http://www.com • SAP Press Æ http://www.sap-press.