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 Introducción Ingresando al sistema Conociendo las transacciones más importantes El Menú de SAP NetWeaver Diccionario de Datos Introducción Elementos del Diccionario de Datos Creando una tabla Creando un dominio Creando un elemento de datos Creando una vista de actualización Creando una ayuda de búsqueda Creando una estructura Creando una Vista Programación en ABAP Introducción Estructura de un programa ABAP Declaración de variables y tablas internas Selección de datos Lectura de datos en tablas internas Operadores de comparación Operaciones en tablas internas Copiar tablas internas Ordenar tablas internas Estructuras de Control Trabajando con Cadenas de Texto Variables de Sistema Modularización de programas Depuración de programas Programas de ejemplo SapScript Introducción Creando un formulario Crear una página principal 7 7 8 12 21 23 23 23 26 37 38 50 60 65 66 70 70 71 78 83 86 89 98 104 108 110 111 119 121 129 138 159 159 159 161 4 Crear ventana en página Crear párrafo por defecto Creando un programa de impresión Diseñando el formulario Ejecutando el formulario Debugger en SAPScript SmartForms Introducción Creando un estilo Creando un formulario Creando un programa de impresión Ejecutando el formulario Crear una tabla Screen Painter y Menu Painter Introducción Screen Painter Controles del Screen Painter Ejemplo de Screen Painter Menu Painter Agregando componentes Programación avanzada en Dynpros MatchCodes dinámicos Eliminar registros en un Table Control Escritura/Lectura en un Table Control Trabajando con subScreens Utilizando listas desplegables Leyendo datos de un Dynpro Módulos de Función y BAPIS Introducción Módulos de Función Creando nuestra primera función Llamando funciones desde un programa Introducción BAPIS ALV (ABAP List Viewer) Introducción Creando un ALV Agregando una cabecera al reporte Eventos ALV Pintemos con colores Barra de menú en ALV ABAP Orientado a Objetos 163 166 168 175 182 185 187 187 187 191 196 200 202 210 210 210 213 215 228 235 240 240 246 249 259 272 278 280 280 280 288 290 292 292 292 301 308 313 320 328 5 Introducción ¿Qué es la Orientación a Objetos? Conceptos básicos de POO Como programar en ABAP Objects Componentes Orientados a Objetos Crear un ALV Grid OO Agregar validaciones y eventos Crear un ALV Tree OO Agregar validaciones y eventos Crear un ALV Object Model Agregar validaciones y eventos Cargar Imágenes en Dynpros Leer PDF’s Comprimir (zip) archivos Crear un Control de Texto WebDynpro Introducción Creando nuestro primer WebDynpro BSP Introducción Creando nuestro primer BSP ABAP y XML Scripting in a Box SAPLink Integración PHP-NetWeaver Introducción Instalando el SAPRFC Comunicándonos con NetWeaver Integración Ruby-NetWeaver Introducción Instalando el SAP:Rfc Comunicándonos con NetWeaver Donde conseguir el SAP NetWeaver Sneak Preview Bibliografía y agradecimientos Enlaces Web 328 328 329 335 351 351 365 379 399 409 416 421 430 438 451 458 458 458 489 489 489 501 518 521 525 525 526 527 539 539 540 540 546 547 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 Usuario Desarrollador. Con este usuario Usuario de Diccionario de Datos. Con este usuario, nuevos usuarios en NSP. BCUSER DDIC podemos programar en NSP. 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 NSP. 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 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 SE38 (Editor ABAP) Este es el entorno de programación del NSP. 12 .Conociendo las transacciones más importantes 1.. Aquí podemos crear nuestro programas o includes (Programas no ejecutables que se incluyen dentro de programas ejecutables). SE11 (Diccionario ABAP) En esta transacción podremos crear. visualizar o modificar Tablas.2. 13 . Vistas. Estructuras y Ayudas para Búsqueda.. Dominios. SE16 (Browser de Datos) Es donde visualizamos los datos incluidos en Tablas o Vistas. 14 .3.. 4.SE71 (Form Painter) Nos permite crear formularios de Impresión.. 15 . ventanas. Se puede utilizar cualquiera de los dos. Certificados.. 16 . insertar imágenes. aunque depende de cada desarrollador. 5. tabuladores. Facturas.Podemos definir páginas. tipos de párrafo. El SmartForms es la nueva versión del SapScript. Cheques. márgenes.SmartForms (Form Painter Avanzado) Nos permite crear formularios de Impresión. Por lo general se utilizan para generar Cartas de Pago a Bancos. .SE51 (Screen Painter) Nos permite diseñar pantallas para crear programas interactivos.6. 17 . 7.SE41 (Menu Painter) 18 .. . así como modificar o visualizar funciones ya creadas.8. 19 .SE37 (Function Builder) Nos permite crear funciones para utilizar en nuestros programas. 20 . El menú de SAP NetWeaver En todas las transacciones. accederemos a ella en la misma ventana. Si escribimos /n antes de la transacción. Imprimir. Buscar más. Cancelar el programa o transacción. accederemos a ella en una nueva ventana. Salir del programa o transacción. contamos con una barra de menú. Retroceder una pantalla. Ej: /nSE38 ó /oSE16. Veamos cuales son: Equivale a hacer clic en la tecla Enter. que nos permite interactuar con las aplicaciones de NetWeaver. Grabar. Buscar. 21 . Aquí es donde se escribe la transacción a la cual queremos acceder. Si escribimos /o antes de la transacción. 22 . Configuraciones GUI. Ayuda.Se habilitan en Tablas y sirven para avanzar o retroceder registros. Crea un acceso directo en el escritorio. Abre una nueva ventana o sesión del NetWeaver. Elementos del Diccionario de Datos 1. estructuras. todo es manejado por tablas. que en NetWeaver. funciones.. dominios. es decir..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. Cabe destacar. Es decir.. elementos de datos. así como la manera de crear cada uno de sus diferentes componentes. es el repositorio en el cual se almacenan todas las tablas. ayudas de búsqueda. existe físicamente en la base de datos. Vamos a dar un breve repaso de todos los conceptos que intervienen en el diccionario de datos. cada tabla transparente definida en el Diccionario de Datos.Diccionario de Datos Introducción El Diccionario de Datos en NetWeaver.Y eso que hablamos de la versión Sneak Preview. includes y elementos del diccionario son almacenados en tablas. Es el tipo más común de tabla y es el más utilizado por los desarrolladores ABAP. 23 .348 tablas standard. NetWeaver cuenta con 63. todos los programas. la versión real del NetWeaver debe tener por lo menos el doble o triple de tablas. Por lo tanto. Es decir.• Tablas Reunidas (Pooled Tables): Posee una relación de muchos a uno con una tabla de la Base de Datos. contienen los nombres del campo. contienen las características técnicas de un campo. Este tipo de tablas son definidas por SAP y su uso se limita a tablas que son accedidas constantemente. son definidas por SAP. 24 .. como las tablas del sistema. Poseen una relación de muchos a uno con una tabla de la Base de Datos. se encuentran almacenadas físicamente en la Base de Datos en tablas llamadas Pool Tables. requiere a su vez de un Dominio. tales como su longitud y su tipo de dato. Muchas tablas Pool. es similar a una Pool Table. Una definición de Elementos de Datos. existen muchas tablas en el Diccionario de Datos. 2. Los Elementos de Datos. • Tablas Racimo (Cluster Tables): Una tabla racimo. Los Dominios. y cada campo debe de estar asignado a un Elemento de Datos o a un Tipo Predefinido. por una tabla que existe físicamente en la base de datos. Muchas tablas racimo son almacenadas físicamente en la Base de Datos en tablas llamadas Table Cluster.Componentes de una tabla Las tablas están compuestas por campos. Este tipo de tablas. así como también almacenan los valores de la ayuda en línea. son reutilizables. Creación de Objetos del Diccionario Para acceder al Diccionario de Datos. sin que esto genere algún tipo de conflicto. 25 . Lo que significa que pueden estar definidos en más de una tabla.Tipos de Datos para Dominios Tanto los Elementos de Datos como los Dominios. deberemos ingresar a la transacción SE11. Con estas 26 .Creando una tabla Para propósitos del libro. modificar. llamadas ZLENGUAJES_PROG y ZENTORNOS_PROG..En esta transacción podremos visualizar. vamos a crear 2 tablas. eliminar o crear los siguientes elementos: • • • • • • Tablas Transparentes Vistas Estructuras Dominios Elementos de Datos Ayudas para búsqueda 1. Como se habrán dado cuenta. deberemos ingresar una descripción para la tabla. • Presionamos el botón Create. hacemos lo siguiente: • Escribimos el nombre de la tabla que queremos crear. se nos presenta una ventana. puesto que es la única restricción que nos da NetWeaver al momento de crear cualquier elemento o componente. vamos a trabajar todos los ejemplos del libro. así que es muy importante que las creen para poder seguir los ejemplos con mayor facilidad.tablas. ambas tablas comienzan con el prefijo “Z”. Para crear nuestra primera tabla. En este momento. 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. en la cual. 27 . En nuestro caso. así que es la que vamos a utilizar nosotros. Cuando grabemos. que nos es más que una tabla donde se organizan los desarrollos por tipos. nos pide asociar nuestra tabla a un Package (Paquete). son los tipo C y L.Clase de Entrega Casi en un 99% de las veces. escogeremos la opción Display/Maintenance Allowed para poder generar una Vista de Actualización más adelante. También debemos escoger el tipo de Mantenimiento que se le va a dar a la tabla. o 28 . la única que podríamos utilizar además de esta. nos encontraremos con una ventana muy común en NetWeaver. se utiliza la clase de entrega A. Esta ventana. Tenemos dos opciones. En todo caso. utilizamos el paquete $TMP que es local y por lo tanto no transportable (Es decir. 29 . así que debemos hacer lo siguiente: • Abrimos una nueva ventana o sesión con /oSE80 (Object Navigator). o podemos crear nuestro propio Package en donde almacenaremos todos los componentes que creemos en el libro. • Con un clic derecho. vamos a crear nuestro propio Package. no puede salir del ambiente DEV de desarrollo). Obviamente. abrimos un menú emergente y escogemos Create Package. Y escogemos la opción Package de la lista. • NetWeaver nos solicita que ingresemos una Orden de Transporte para almacenar nuestro nuevo Package. 30 .• Llenamos los campos y presionamos el botón Save. presionamos el botón Create Request. • Ingresamos una descripción y grabamos. • Una vez creada y asignada la Orden de Transporte. presionamos el botón Continue o presionamos Enter. 31 . 32 .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. • En nuestro caso. presionando el botón Start Search o presionando la tecla Enter. lo mejor es escribir Z* para que nos muestre solamente los paquetes creados por nosotros o por el sistema (Definidos para los usuarios). 33 . • Escogemos nuestro Package con un doble clic para que quede asignado a nuestra tabla. o solicitar que se muestren todos los disponibles.• Podemos ingresar el nombre del Package. Ahora. entonces la misma orden aparecerá por defecto. Presionamos el botón Continue o la tecla Enter. Como creamos una orden al momento de crear el Package.• Presionamos el botón Save. Debemos ir a la pestaña Fields (Campos). para poder agregar los campos necesarios para nuestra tabla. podemos continuar con la creación de nuestra tabla. 34 . Y nos va a aparecer la ventana solicitando una Orden de Transporte. El primer campo que vamos a utilizar es el MANDT. se llamará Id. la interfaz de la pantalla cambia un poco. Esto es porque vamos a utilizar un Predefined Type (Tipo Predefinido). • Hacemos clic en el botón Predefined Type. El segundo campo. Como se darán cuenta. en el gráfico no he llenado el campo Data Element (Elemento de Datos). que identifica al ambiente en el cual estamos trabajando (Y que es un campo llave). para el campo Id. Y como podemos ver. 35 . y será el encargado de identificar a cada uno de los registros (También es un campo llave). • El siguiente campo también necesita un tipo predefinido. así que abrimos otro modo para antes continuar ZLENGUAJES_PROG. con una de tabla que con llamaremos la tabla ZENTORNOS_PROG. Este estará relacionado poder crearla. así que lo llamamos Nombre y lo definimos como un CHAR de longitud 15. • Al igual que en la tabla ZLENGUAJES_PROG. además. agregamos una pequeña descripción del campo. los 2 primeros campos serán Mandt y Id. 36 . • El siguiente campo se llamará Entorno.• Queremos que el tipo de dato sea CHAR y tenga una longitud de 3. y no tendrá asociado un Tipo Predefinido. lo llamaremos ZD_ENT_NAME. abrimos una nueva ventana en la SE11 y nos posicionamos en Domain (Dominio). se llamará Nombre..Creando un Dominio A este Dominio. Llenamos los campos como se muestra en la imagen. sino que contará con un Elemento de Datos y un Dominio. 37 . 2.• El tercer campo. Para esto. Lo llamaremos ZE_ENT_NAME.. Llenamos los datos como se muestra en la figura.Creando un Elemento de Datos • Una vez creado el Dominio. aparece una ventana preguntándonos por el Tipo de Dato que queremos crear. 38 . pasamos a crear nuestro Data Element (Elemento de Datos). utilizando el Dominio que creamos. de que al momento de presionar el botón Create.Lo grabamos y lo activamos utilizando el botón Activate (Activar) o presionando Crtl + F3. 3. En la misma transacción. Se dará cuenta. nos posicionamos en Data Type (Tipo de Dato). Lo dejamos como Data Element y presionamos Enter. Grabamos y activamos.Ahora. que no es más que la descripción del Elemento de Datos. E • Grabamos y ahora debemos llenar los datos de Technical Settings (Caraterísticas Técnicas) Goto Technical Settings o presionar Crtl + Shift + F9. • Como estábamos ingresando Tipos Predefinidos. • Regresamos a la ventana donde estábamos creando la tabla ZENTORNO_PROG. debemos presionar el botón Data Element ingresar el nombre de nuestro Elemento de Datos. debemos pasar a la pestaña Field Label (Etiqueta de Campo). Y luego debemos 39 . . La llenamos como se muestra en la figura. determina la cantidad de espacio que se reservará inicialmente para la tabla. Para nosotros. así que 0 es la opción a tomar. 40 . Grabamos y retrocedemos para poder acceder al Enhacement Category. nuestra tabla no contendrá mucho datos.llenar el Enhacement Category (Categoría de Ampliación) Extras Enhacement Category. El campo Size Category (Categoría de Tamaño). en nuestro caso. El campo Data Class (Clase de Datos) especifica el área física en la cual se va a crear la tabla. el valor por defecto siempre será APPL0. Esto nos mostrará una ventana. • Nos posicionamos sobre el campo Entorno y presionamos el botón Foreign Keys (Llaves Foráneas) . que veremos a continuación. le decimos que no. 41 . para poder ingresar nuestro Elemento de Datos para el campo Entorno.Esto sirve para definir si la tabla puede ser modificada con campos adicionales. • Regresamos a nuestra tabla ZLENGUAJES_PROG y presionamos el botón Data Element. En nuestro caso. puesto que son tablas que hemos creado como ejemplo para el libro. Grabamos y activamos. presionamos Yes (Sí) o presionamos Enter. El sistema nos propone crear una asignación entre las tablas. Y presionamos Enter. escribimos el nombre de nuestra tabla ZENTORNOS_PROG.En el campo Check Table (Tabla de Verificación). 42 . Recibimos este mensaje. Dejamos la ventana. se llama CONEX_SAP y determina si el lenguaje posee algún tipo de conexión con SAP. como se muestra en la figura. Para esto. no existe en la tabla • El ultimo campo. 43 . porque la llave completa de la tabla ZENTORNOS_PROG ZLENGUAJES_PROG. Ahora. pasamos a la pestaña Value Range (Rango de Valores). es simplemente un CHAR de 1. 44 .vamos a crear nuevamente un Dominio (ZD_CONEX_SAP) y un Elemento de Datos (ZE_CONEX_SAP). Y llenamos solamente dos valores. Como ven. Llenamos la pestaña Field Label (Etiqueta de Campo). • Llenamos la Características Técnicas. activamos y creamos nuestro Elemento de Datos. • De vuelta en la tabla ZLENGUAJES_PROG. agregamos el campo CONEX_SAP con su respectivo elemento de datos.• Grabamos. grabamos y activamos. la Categoría de Ampliación. grabamos y activamos. 45 . + S. 46 . Y grabamos con el botón Save (Guardar) o presionamos Crtl. Nos vamos a la transacción SE16 (Browser de Datos).Ahora que tenemos nuestras dos tablas listas. y presionamos el botón Create Entries (Crear Entradas) presionamos F5. es hora de agregar algunos datos. o Ingresamos algunos cuantos valores. Colocamos el nombre de nuestra tabla de entornos. En nuestro caso. En esta ventana. así que dejamos esos campos en blanco.Una vez que hemos terminado de insertar registros. 47 . podemos hacer un filtro ya sea por Id o por Entorno. Para poder ver los registro que hemos creado. podemos presionar el botón Table Contents (Contenido de Tabla) o presionar Enter. Presionamos el botón Execute (Ejecutar) o presionamos F8. queremos ver todos los valores. retrocedemos presionando el botón Back (Atrás) o presionando el botón F3. Cuando se posicionen en el campo Entorno. 48 .Tenemos 3 registros grabados en la base de datos. se darán cuenta de algo interesante. Ahora. Para esto debemos hacer clic en ese botón o presionar F4. Seguimos el mismo procedimiento. lo cual nos indica que existen valores de los cuales podemos escoger. Aparece un pequeño botón al final del campo. es el turno de la tabla ZLENGUAJES_PROG. si ingresamos cualquier otro valor. Cabe destacar que los valores que están en la tabla ZENTORNOS_PROG.Esos son los registros que ingresamos en la tabla ZENTORNOS_PROG y que ahora podemos insertar en nuestra tabla ZLENGUAJES_PROG. Lo mismo sucede con el campo CONEX_SAP. son los únicos valores válidos. el sistema nos mostrará un mensaje de error. 49 . es decir. 50 ..Ingresamos algunos datos y estamos listos. que ahora vamos a crear una vista de actualización. es un poco tedioso. debemos regresar a la transacción SE11 y modificar la tabla ZLENGUAJES_PROG. Seguramente.. les parecerá que ingresar los datos así.No se preocupen.Creando una Vista de Actualización Para crear nuestra vista de actualización. En el menú. vamos a Utilities (Utilidades) Table Maintenance Generator (Generador de Mantenimiento de Tabla).. Llenamos la ventana como se muestra a continuación. 3. siempre escogemos la primera opción Propose Screen Number(s) (Proponer número(s) de Ventana). 51 .Presionamos el botón Find Scr. En esta ventana. Number(s) (Buscar Número(s) de Pantalla) o presionamos Shift + F7. Grabamos y activamos. o presionamos F6. los dos primeros campos aparecen como 52 . pero como se darán cuenta. Se nos muestra una pantalla más amigable para el ingreso de datos.Finalmente presionamos el botón Create (Crear) SM30. debemos ir a la transacción Y presionar el botón Maintain. Ahora. Debemos hacer clic tanto en el Overview Screen (Ventana de Vista general) como en el Single Screen (Ventana sencilla). Esto es porque al ser Tipos Predefinidos. no poseen un texto descriptivo. Esto lo podemos solucionar fácilmente regresando a la transacción SE11 y al Generador de Mantenimiento de Tabla. 53 .“+”. Veamos primero en el Overview Screen. que por el momento no vamos a hacer nada con esto.Seguramente esta pantalla los asusta un poco. puesto que es código generado automáticamente por el NetWeaver. Debemos hacer clic en el botón Layout (Disposición) cabeceras que tienen un “+”. . pero no se preocupen. sobre todos las 54 . La pantalla del Screen Painter es la que nos interesa. 55 . activamos y retrocedemos dos veces hasta regresar a la ventana del Generador de Mantenimiento de Tabla.Debemos hacer un clic en el botón Display <-> Change (Mostrar <> Cambiar) o presionar F1. escribimos lo siguiente Y en la segunda columna: Grabamos. Ahora. nos colocamos sobre la primer columna y en la ventana que dice Text (Texto). Hacemos doble clic en Single Screen. Una vez hecho esto. 56 . nos vamos a la transacción SM30 y veremos que los símbolos “+” han sido reemplazados por los textos correctos. regresamos a la transacción SE11 para crear una nueva y última tabla con las siguientes características. para hacer las cosas más interesantes y poder trabajar mejor los ejemplos del libro. activamos y regresamos nuevamente. Grabamos. Ahora. modificando los símbolos “+”.Y repetimos la operación. En otra ventana. creamos un dominio para el código del lenguaje de programación. Ahora. 57 . creamos un Elemento de Datos llamado ZE_ID_LENGUAJE.La tabla se llamará ZPROGRAMAS y contendrá algunos programas que hemos hecho utilizando los lenguajes de programación que hemos creado. llamado ZD_ID_LENGUAJE. 58 .Regresamos a la tabla ZPROGRAMAS y tendremos la siguiente estructura: Para que esto funcione correctamente y podamos hacer una asociación entre las tablas debemos ZPROGRAMAS modificar la y tabla ZLENGUAJES_PROG. 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 . lo cual no nos va a ayudar de mucho. en una nueva ventana. 4. solamente vamos a ver el código.. así que hora de crear una ayuda de búsqueda. al momento de querer elegir un lenguaje de programación. actualizamos las Características Técnicas y la Categoría de Amplicación y activamos la tabla.Creando una Ayuda de Búsqueda Para esto.Grabamos. Como solamente hemos asignado el campo Id a nuestra tabla. Y escogemos la opción Seach Help (Ayuda de búsqueda). Elegimos la primera opción. 60 . vamos a la transacción SE11. 61 . creamos un Dominio y un Elemento de Datos como se muestra a continuación.Como pueden ver. el campo Nombre tiene asignamos un elemento de datos. así que nuevamente. Grabamos y activamos nuestra ayuda de búsqueda y la probamos con presionando el botón Test (Prueba) o presionando F8. 62 . Nos posicionamos en el campo Id. presionamos Enter porque queremos ver todos los registros disponibles. Nuestra ayuda de búsqueda está terminada. así que regresamos a la tabla ZPROGRAMAS a la pestaña Entry Help/Check (Entrada de Ayuda/Verificación).En esta ventana. y presionamos el botón Search Help . 63 . en este caso. podemos filtrar por Id o por Nombre del lenguaje. En la transacción SE16 agregamos algunos cuantos registros.Asignamos la ayuda de búsqueda que creamos. Grabamos y activamos. 64 . creamos nuestra estructura llamada ZSLENGUAJES_PROG. Esto nos va a ser útil al momento de desarrollar nuestros programas. es decir. que no es otra caso que una tabla que solamente contiene una cabecera.. podremos ver tanto el código como el nombre del Lenguaje. Finalmente. 65 . al hacer F4 en el campo Id. en el campo Data type. no puede almacenar registros.Como podemos ver.Creando una Estructura En la transacción SE11. puesto que vamos a poder contar con la estructura sin utilizar memoria adicional de la base de datos. 5. nuestra tabla contendrá los siguientes registros. Con esto terminamos y podemos crear una estructura. 6. creamos nuestra vista en el campo VIEW (Vista). . el Enhacement Category (Categoría de ampliación). aunque quitamos el campo MANDT.Creando una Vista Dentro de la transacción SE11. 66 . Nos va a pedir.. Llamada ZVLENGUAJES_PROG. se nos muestra una ventana en donde debemos elegir Structure Utilizamos los mismos componentes que en la tabla ZLENGUAJES_PROG.Cuando presionamos Create (Crear) (Estructura). lo agregamos para poder activar. Grabamos y activamos. puesto que el Database view es el más utilizado. debemos de llenar los campos que vamos a utilizar para relacionar las tablas que vamos a utilizar en la vista. en este caso. Los demás tipos no los vamos a ver en este libro. 67 . ZPROGRAMAS y ZLENGUAJES_PROG. Primero.En la ventana que aparece. elegimos Database view (Vista de Base de Datos). Ejecutamos y vemos los datos generados por la Vista. Definimos los campos que queremos que se muestren en la vista.En la pestaña View Flds (Campos de la Vista). Los mensajes de advertencia. Una vez que la Vista está activa. Se darán cuenta de que el sistema no envía a la transacción SE16. o presionando Ctrl. podemos obviarlos. podemos comprobar los valores presionando el botón Contents (Contenidos) + Shift + F10. 68 . Grabamos y activamos. dominios o vistas. elementos de datos.Con esto. 69 . ya pueden crear sus propias tablas. terminamos el capítulo dedicado a Diccionario de Datos. Ahora. es el lenguaje de programación propietario de SAP AG. por lo cual al momento de programar. 70 . aunque con el tiempo se el agregaron funcionalidades para convertirlo en un lenguaje orientado a objetos. Hasta la versión 45B. en versiones posteriores de NetWeaver.0. En cuanto a la sintaxis de lenguajes. era un lenguaje procedural. El NetWeaver actualmente está en la versión 7. En el presente capítulo. PASCAL y SQL Server. que era muy utilizado para el desarrollo de aplicaciones empresariales. con el cual se desarrollan aplicaciones que son integradas al NetWeaver. Cabe de destacar que muchos de los componentes de NetWeaver han sido desarrollados utilizado ABAP. El ABAP. vamos a revisar los principales componentes del ABAP. se pueden mezclar ambas tecnologías sin mayores problemas. el ABAP. aunque como es de suponerse. viene a ser una especie de nieto del COBOL (Common Object Business Oriented Language). lo cual nos permite hacer modificaciones que otro tipo de sistemas serían imposibles. lo cual significa que nos permite trabajar con ABAP Objects de manera muy completa. se adicionarán algunos componentes extras.0.Programación en ABAP Introducción ABAP (Advances Business Application Programming). podemos tomarlo como un híbrido entre COBOL. así como la estructura de los programas que se crean con el. Recodemos que debemos utilizar la letra Z antes del nombre del programa. reserva el nombre Z para los programas que son creados por los clientes y no por los mismos trabajadores de SAP. debemos ingresar a la transacción SE38. y especificar el nombre del programa que queremos crear. 71 . 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. Cuando presionamos el botón Create (Crear). Esto es porque SAP. el sistema nos mostrará la siguiente ventana. En Type (Tipo) siempre escogemos Executable program (Programa ejecutable) y en Status (Estado). 72 . elegimos ZARTE_PROGRAMAR. que es donde vamos a poder crear nuestros programas. nos va a pedir el paquete al el desarrollo. El sistema. que existen ciertos comentarios. que debemos colocar en todos nuestros programas. elegimos la creamos puesto que se nos muestra por defecto (Siempre y cuando no hayamos creado otras ordenes). Y cuando nos pida la orden de transporte. elegimos SAP Standard Production Program (Programa Standard SAP para Productivo). nos envía al Editor ABAP. para poder definir algunos bloques importantes. Al presionar el botón Save cual queremos asignar . Debemos tener claro. 73 . Para empezar. debemos incluir por ejemplo. quien está creando el programa y cuando. La primera y única línea que nos muestra el editor es REPORT y el nombre de nuestro programa. luego de esto. veremos la sintaxis de ABAP y podremos hacer programas más complejos. que simplemente solicite al usuario un texto y lo imprima en pantalla.En el espacio de comentario. Esto indica que se trata de un programa ejecutable. vamos a hacer un programa muy simple. significa que va a contar con un título definido por nosotros. *&----------------------------------------------------* *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRUEBA WITH FRAME TITLE TEXT-T01. PARAMETERS: TEXTO(30) TYPE C. WITH FRAME TITLE. significa que el área de los parámetros de selección va a estar rodeados por un marco y TITLE. SELECTION-SCREEN END OF BLOCK PRUEBA. nos permite definir un espacio en donde van a ir los parámetros de entrada de nuestro programa. WRITE: TEXTO. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. en este caso 74 . * *=====================================================* * *=====================================================* El SELECTION-SCREEN BEGIN OF BLOCK. es el nombre que le estamos asignando al bloque de parámetros. *& Fecha creación: 14 de Noviembre del 2007 REPORT ZDUMMY_PRIMER_PROGRAMA. PRUEBA.*&----------------------------------------------------* *& Report ZDUMMY_PRIMER_PROGRAMA * * * *&----------------------------------------------------* *& Creado por: Alvaro "Blag" Tejada Galindo. podemos utilizar 2 tipos de parámetros: • PARAMETERS solamente un valor. simplemente deberemos hacer doble clic en el texto. TEXT-T01. que nos indica que es un texto del sistema y T01. 75 Son parámetros simples que aceptan . grabamos y activamos. Si no lo hemos creado. nos aparecerá la siguiente ventana: Simplemente.TEXT-T01. ingresamos el texto. • SELECT-OPTIONS Son parámetros compuestos que aceptan un rango de valores. es el nombre de dicho texto. Para poder modificarlo. lo podemos separar en dos partes TEXT. Dentro del bloque que hemos definido para los parámetros. es un CHAR de 30 caracteres. 76 . veremos el parámetro de entrada que definimos.El parámetro que hemos utilizado en este programa. si queremos cambiar el texto que muestra nuestro parámetro. Ahora. Si activamos y ejecutamos el reporte (Presionando la tecla F8). deberemos de ingresar al siguiente menú. Goto Text Elements Selection Texts. TEXTO(30) TYPE C. Aquí. lo activamos y listo. 77 . lo grabamos. deberemos de ingresar el texto que queremos que tenga nuestro parámetro. Ahora. volvamos a ejecutar el reporte. nos indica que va a comenzar la ejecución de nuestro programa. WRITE: TEXTO. Ese fue nuestro primer y más simple programa en ABAP. utilizamos la sentencia DATA. que lo único que hace es separar un espacio en memoria. DATA: TEXTO TYPE C. el valor que hemos ingresado en el parámetro de entrada TEXTO. Declaración de Variables y Tablas Internas Para poder declarar variables. significa que vamos a escribir en la pantalla. es aquí donde colocamos toda la lógica. 78 .El START-OF-SELECTION. Además.Aquí estamos diciendo que vamos a crear una variable llamada TEXTO. podemos utilizar campos de tablas para poder hacer la declaración de variables. Entre los tipos de datos que nos ofrece el ABAP. 4 8 8 0 0 ‘0. DATA: TEXTO(30) TYPE C. tenemos: C N D T X I P F STRING XSTRING Character Numeric String Date (YYYYMMDD) Time (HHMMSS) Byte (Hexadecimal) Integer Packed Integer Floating point number String Byte Sequence Variable Variable Empty string Empty X String Adicionalmente. y que va a ser de tipo C (Caracter).0’ 1 X’00’ 6 ‘000000’ 1 1 8 Space ’00…0’ ‘000000000’ 79 . podemos especificar su tamaño. que son uno de los elementos más valiosos del ABAP. TYPES: BEGIN OF TY_TABLA. vamos a utilizar y aprender solamente las nuevas sintaxis que se nos ofrecen gracias a la creación del ABAP Objects. DATA: T_TABLA TYPE STANDARD TABLE OF TY_TABLA. esto no es posible. Las tablas internas. … END OF TY_TABLA. En versiones anteriores.DATA: V_CARRID TYPE SPFLI-CARRID. Ahora veamos las tablas internas. V_CARRID es un CHAR de 3 caracteres. 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 TABLA. Por lo tanto. Con la introducción de NetWeaver. 80 . así que de ahora en adelante. En este caso. podíamos utilizar la siguiente sintaxis: DATA: BEGIN OF TABLA OCCURS 0. en versiones anteriores. que SAP decició eliminar la cabeceras completamente. es decir. Para los que ya conocen ABAP. utilizando el DATA. Es por eso. de la manera que hemos visto. TYPES: TEST TYPE STRING. lo cual facilitaba la lectura de datos. DATA: T_SPFLI TYPE STANDARD TABLE OF SPFLI. un tipo de tabla interna y luego. podiamos crear tablas internas con líneas de cabecera. DATA: T_SPFLI TYPE STANDARD TABLE OF TY_SPFLI. debemos crear un TYPE. 81 . en ABAP Objects. Para los que no conocen ABAP. ni tampoco WITH HEADER LINE. Además de crear tablas internas. pero que al mismo tiempo ocasionaba problemas de performance. está prohibido utilizar cabeceras o workareas. no utilizamos ni OCCURS 0. Esto podemos hacerlo de dos maneras. INCLUDE STRUCTURE SPFLI. TYPES: BEGIN OF TY_SPFLI. creamos una tabla interna que haga referencia a nuestro tipo de tabla. TYPES: END OF TY_SPFLI. se darán cuenta de que no hemos creado la tabla con una cabecera. Esto es porque. dependiendo de si queremos o no incluir campos adicionales. Es decir. podemos también incluir estructuras completas de Base de Datos.Primero. Claro. NOMBRE TYPE STRING. TYPES: BEGIN OF TY_TEST. ID(3) TYPE C. porque tenemos que utilizar el TYPE STANDARD TABLE. TYPES: BEGIN OF TY_TEST. muy simple. porque tenemos disponibles más tipos de tablas. END OF TY_TEST. tenemos 3 tablas internas. DATA: TEST TYPE STANDARD TABLE OF TY_TEST. 82 . EDAD TYPE I. DATA: TEST_S TYPE SORTED TABLE OF TY_TEST WITH UNIQUE KEY ID Como pueden ver. DATA: TEST TYPE STANDARD TABLE OF TY_TEST. lo hacemos de la siguiente forma. NOMBRE(30) TYPE C. si queremos crear una tabla interna que tenga datos propios. Seguramente se habrán dado cuenta y sobre todo se preguntarán. DATA: TEST_H TYPE HASHED TABLE OF TY_TEST WITH UNIQUE KEY ID. EDAD TYPE I. END OF TY_TEST. solo he utilizado este tipo de tablas algunas cuantas veces en toda mi carrera. SELECT SINGLE NOM_PROG INTO NOMBRE FROM ZPROGRAMAS WHERE ID_PROG EQ '001'. Aunque en el caso de ABAP. en lo personal. depende del nivel de nivel de datos o de la complejidad del programa. tenemos mayor flexibilidad para poder almacenar los datos.TEST TEST_H TEST_S Tablas Standard. En Variables: DATA: NOMBRE TYPE ZPROGRAMAS-NOM_PROG. De rápido acceso. pero no puede Sorted table. 83 . el uso de tablas Hashed o Sorted. siempre está ordenada. De rápido acceso. mediante campos. En realidad. podemos utilizar la clásica sentencia SELECT. Selección de Datos Al igual que en SQL. Puede ser accedida mediante un índice o Tabla de tipo hashed. para poder seleccionar datos. ya sea en Variable o en Tablas internas. ser accedida mediante un índice. no puede ser accedida mediante un índice. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. SELECT NOM_PROG INTO TABLE T_PROGRAMAS FROM ZPROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. 84 . END OF TY_PROGRAMAS. también podemos utilizar INNER JOINS para hacer nuestras consultas. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. creamos un TYPE. luego una tabla interna y finalmente leemos todas las instancias del campo NOM_PROG dentro de nuestra tabla interna. END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. En esta caso.Declaramos una variable llamada NOMBRE del tipo del campo NOM_PROG de la tabla ZPROGRAMAS. Claro. En Tablas internas: TYPES: BEGIN OF TY_PROGRAMAS. Hacemos un SELECT SINGLE para obtener un registro cuyo campo ID_PROG sea igual a 001. 85 . CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. Esto lo podemos solucionar utilizando un INTO CORRESPONDING FIELDS. el SELECT va a estar incompleto y los registros pueden guardarse donde no les corresponde. SELECT NOMBRE ENTORNO NOM_PROG INTO CORRESPONDING FIELDS OF TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). Ahora. pero no queremos seleccionarlo. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. que lo que hace es almacenar los registros en los campos correspondientes. supongamos que tenemos un campo más en nuestra tabla interna.DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_PROGRAMAS. así que lo mejor es evitarlos. aunque claro. esto afecta el performance de nuestros programas. entonces. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). Para eso. Para los que han programado alguna vez en C++. Aunque. Con esto. los Fields-Symbols. es decir. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. END OF TY_PROGRAMAS. almacenas la dirección en memoria de una variable. creamos una referencia a la tabla T_TABLA. Por lo general. Estamos hablando de los Field-Symbols. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. debemos de leerlas para poder hacer algo con ellas.Lectura de datos de Tablas Internas Una vez que tenemos datos en nuestras tablas internas. sin el cual no podríamos hacer mucho en ABAP. son muy parecidos a los punteros. con lo cual ganamos mucho performance al hacer lecturas de tablas internas. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. 86 . debemos conocer un elemento muy importante. FIELD-SYMBOLS: <FS_TABLA> LIKE LINE OF T_TABLA. antes de eso. • LOOP AT TYPES: BEGIN OF TY_PROGRAMAS. la cual contiene únicamente una línea de cabecera. los utilizamos para crear cabeceras de tablas internas. contamos con dos opciones. por lo cual la lectura de la tablas es mucho más veloz. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. lo que estamos haciendo es pasar simplemente la cabecera de ese registro. Al hacer un LOOP AT. 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>. ENDLOOP. utilizando un WRITE imprimimos el contenido del campo NOM_PROG. y al asignar cada uno de estos registros a nuestro Field-Symbol. Finalmente. 87 . WRITE:/ <FS_PROGRAMAS>-NOM_PROG.DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. lo que hacemos es leer cada uno de los registros almacenados en nuestra tabla interna. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS WITH KEY NOMBRE = 'PHP' ASSIGNING <FS_PROGRAMAS>. como podemos ver. END OF TY_PROGRAMAS.• READ TABLE TYPES: BEGIN OF TY_PROGRAMAS. al utilizar un READ TABLE. 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. leemos un solo registro de nuestra tabla. podemos utilizar 88 . En este caso. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. LT >=. EQ <>. LE Igual a Distinto a Mayor que Menor que Mayor igual Menor igual Ambos tipos de comandos son equivalentes. GE <=. para esto. WRITE:/ ‘Viva PHP!’.un Indice o también un Campo para leer el contenido y asignarlo a nuestro Field-Symbol. contamos con los siguientes comandos. Que decir: IF NOMBRE == ‘PHP’. 89 . GT <. Operadores de Comparación Un proceso muy común. por lo tanto es lo mismo decir: IF NOMBRE EQ ‘PHP’. es el comparar valores entre variables o tablas internas. ENDIF. =. NE >. WRITE:/ ‘Viva PHP!’. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. END OF TY_PROGRAMAS. Para poder afianzar los conocimientos adquiridos hasta el momento.ENDIF. *=====================================================* * DECLARACION DE VARIABLES DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 90 . ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. *=====================================================* * DECLARACION DE TABLES TABLES: ZPROGRAMAS. vamos a crear una pequeña aplicación. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01.OF T_PROGRAMAS.33 'Programa'. WRITE:/ SY-ULINE(45). SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. SELECTION-SCREEN END OF BLOCK PRG. WRITE:/ <FS_PROGRAMAS>-NOMBRE. *=====================================================* * START-OF-SELECTION START-OF-SELECTION.<FS_PROGRAMAS>-ENTORNO.17 'Entorno'. <FS_PROGRAMAS>-NOM_PROG. * *=====================================================* * *=====================================================* 91 . LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. 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:/1 'Lenguaje'. ENDLOOP. 92 . END OF TY_PROGRAMAS. TABLES: ZPROGRAMAS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. TYPES: BEGIN OF TY_PROGRAMAS. TYPES indica que vamos a crear un tipo de tabla definido por nosotros. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ZDUMMY_PRIMER_PROGRAMA es el nombre de nuestro programa. TABLES indica que vamos a utilizar una tabla para hacer referencia a un campo en el SELECTION-SCREEN. indica que no queremos que el título del programa se muestre en el output del reporte. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO.Analicemos un poco el programa antes de ejecutarlo y ver el resultado. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. NO STANDARD PAGE HEADING. REPORT indica que estamos creando y ejecutando un programa. SELECTION-SCREEN BEGIN OF BLOCK indica el inicio de un bloque de parámetros. TY_PROGRAMAS es el nombre del tipo de tabla que creamos y al cual va a hacer referencia nuestra tabla interna.DATA indica que vamos a crear una variable o una tabla interna. T_PROGRAMAS es el nombre de nuestra tabla interna. SELECTION-SCREEN END OF BLOCK PRG. 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. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. FIELD-SYMBOLS crea un field-symbol. T_PROGRAMAS es la tabla interna de la cual el field-symbol va a representar la cabecera. PRG es el nombre del bloque de parámetros. 93 . SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. <FS_PROGRAMAS> es el nombre de nuestro field-symbol. TYPE STANDARD TABLE indica que la tabla es de tipo STANDARD. OF indica a que tipo de dato va a hacer referencia nuestra tabla interna. ZPROGRAMAS-ID es el nombre de la Base de Datos y el campo respectivamente. NOMBRE ENTORNO NOM_PROG son los campos que queremos seleccionar. T01 contiene el título. S_ID es el nombre del SELECT-OPTION. SELECT-OPTIONS indica que es un parámetros con rango de valores. 94 . START-OF-SELECTION indica el inicio de nuestro programa. SELECT indica que queremos seleccionar datos. 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.WITH FRAME indica que nuestro bloque de parámetro debe tener un marco (más que nada un tema de visualización). FOR indica que hace referencia a un campo de Base de Datos. TITLE TEXT indica que el bloque de parámetros debe tener un título. SELECTION-SCREEN END OF indica el fin del bloque de parámetros. START-OF-SELECTION. INTO TABLE indica en que tabla interna queremos guardar los datos. 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. ‘Lenguaje’. 1. WRITE:/ SY-ULINE(45). ZLENGUAJES~ID = ZPROGRAMAS~ID indica que el campo ID de ambas tablas va a utilizarse como campo de igualdad. IN indica que el campo del filtro debe de estar dentro de los valores del SELECT-OPTION. S_ID es el SELECT-OPTION contra el cual vamos a validar el campo ZPROGRAMAS~ID. WHERE indica el parámetro de restricción del SELECT. T_PROGRAMAS es la tabla donde vamos a guardar los datos.17 'Entorno'. FROM indica de donde queremos obtener los datos. 95 . WRITE indica que queremos escribir algo en la pantalla. indican las posiciones X en las cuales queremos escribir. ‘Entorno’ y ‘Programa’ son los texto que queremos escribir.33 'Programa'. / indica que luego de escribir en la pantalla queremos hacer un salto de líneas. 17 y 33. WRITE:/1 'Lenguaje'. ZPROGRAMAS~ID es el campo por el cual queremos hacer el filtro. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. T_PROGRAMAS es la tabla interna de la cual vamos a leer los registros. 96 . ENDLOOP indica el fín del LOOP. <FS_PROGRAMAS>-NOM_PROG. Ahora que ya hemos revisado todo el programa línea por línea. El 45 entre paréntesis indica la longitud de la línea. ENDLOOP. <FS_PROGRAMAS> es el nombre del Field-Symbol. ASSIGNING <FS_PROGRAMAS> indica que vamos a asignar el registro leído a un Field-Symbol.SY-ULINE(45) es una variable del sistema que nos permite dibujar una línea. <FS_PROGRAMA>-NOMBRE es el nombre del campo que queremos escribir en la pantalla. podemos ejecutarlo. WRITE:/ <FS_PROGRAMAS>-NOMBRE. LOOP AT indica que vamos a recorrer todos los registros de una tabla interna.<FS_PROGRAMAS>-ENTORNO. WRITE:/ SY-ULINE(45).33 'Programa'. FORMAT COLOR OFF.17 'Entorno'. FORMAT COLOR 5. WRITE:/1 'Lenguaje'. podemos agregar un par de líneas.Si queremos que nuestro programa se vea un poco más colorido. 97 . 5 representa al color verde. FORMAT COLOR OFF indica que ya no queremos seguir pintando el fondo de un color. muchas veces se necesita agregar. ID_PROG TYPE ZPROGRAMAS-ID_PROG. 98 . modificar o eliminar registros (Ya sea porque no nos sirven o porque están duplicados).FORMAT COLOR indica que queremos pintar el fondo de un color. El reporte quedaría así: Operaciones en tablas internas Cuando se trabaja con tablas internas. Veamos como manejar esto: • Agregando registros TYPES: BEGIN OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. Como vemos. END OF TY_PROGRAMAS. Pero como esta no tiene cabecera. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. entonces debemos asignarle una utilizando APPEND INITIAL LINE TO y asignándola a <FS_PROGRAMAS>. 99 . creamos una tabla interna. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. WRITE:/ <FS_PROGRAMAS>-ID_PROG. Luego. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. agregamos los valores a la tabla y al momento de leerla con el índice 1. podemos imprimir los nuevos valores. SKIP 1. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. <FS_PROGRAMAS>-ID_PROG = '006'. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. END OF TY_PROGRAMAS. 100 . WRITE:/ <FS_PROGRAMAS>-ID_PROG. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. WRITE:/ 'Modificamos el registro'. SKIP 1.• Modificando registros TYPES: BEGIN OF TY_PROGRAMAS. estamos utilizando la sentencia SKIP. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. En esta caso solamente 1. Simplemente escribimos el nuevo valor para que se modifique automáticamente. esta sentencia nos permite realizar saltos de línea. • Eliminado registros TYPES: BEGIN OF TY_PROGRAMAS. WRITE:/ <FS_PROGRAMAS>-ID_PROG. 101 . ID_PROG TYPE ZPROGRAMAS-ID_PROG. Tomando el ejemplo anterior. leemos el primer registro y lo asignamos a <FS_PROGRAMAS>.<FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. Podrán ver que además. END OF TY_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. 102 . TYPES: BEGIN OF TY_PROGRAMAS. DELETE T_PROGRAMAS INDEX 1. y como podemos ver. DELETE T_PROGRAMAS WHERE ID_PROG EQ '006'. Ahora. <FS_PROGRAMAS>-ID_PROG = '007'. Asignamos dos registros a nuestra tabla interna. supongamos que tenemos registros repetidos y queremos eliminarlos sin preocuparnos por el índice (Puesto que eliminado por campo. ID_PROG TYPE ZPROGRAMAS-ID_PROG. eliminaríamos todos los registros). END OF TY_PROGRAMAS. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. podemos eliminarlos utilizando ya sea un índice o uno de los campos como parámetro de búsqueda.<FS_PROGRAMAS>-ID_PROG = '006'. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. por lo tanto utilizamos DELETE ADJACENT DUPLICATES para dejar solamente uno de los dos registros. END OF TY_PROGRAMAS. tenemos dos veces el mismo registro. DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS. Entonces debemos hacer algo más. Claro. Como podemos ver. más no el campo NOM_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. 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. <FS_PROGRAMAS>-ID_PROG = '006'. 103 . NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. <FS_PROGRAMAS>-ID_PROG = '006'. TYPES: BEGIN OF TY_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. ID_PROG TYPE ZPROGRAMAS-ID_PROG. Copiar tablas internas Algunas veces. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. Simplemente debemos agregar un COMPARING. 104 . necesitamos copiar el contenido de una tabla interna a otra. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. las tablas tienen la misma estructura o tienen una estructura distinta. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. dos opciones. <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>. En este caso. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. <FS_PROGRAMAS>-ID_PROG = '006'. DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS COMPARING ID_PROG.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. poseen exactamente la misma estructura. haciendo referencia a TY_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. por lo tanto. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS. tenemos y las dos tablas internas ambas T_PROGRAMAS T_PROGRAMAS_AUX.• Copiar tablas con la misma estructura TYPES: BEGIN OF TY_PROGRAMAS. En este caso. Por ello. END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. 105 . T_PROGRAMAS_AUX[] = T_PROGRAMAS[]. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. APPEND INITIAL LINE TO T_PROGRAMAS_AUX 106 . NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. <FS_PROGRAMAS>-ID_PROG = '006'. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG.• 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. END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_PROGRAMAS_AUX. END OF TY_PROGRAMAS_AUX. ID_PROG TYPE ZPROGRAMAS-ID_PROG. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS_AUX. ID TYPE ZPROGRAMAS-ID. TYPES: BEGIN OF TY_PROGRAMAS. Creamos un tipo de tabla llamado TY_PROGRAMAS_AUX al cual le agregamos el campo ID. ENDLOOP. END OF TY_PROGRAMAS_AUX. En vez de eso. debemos hacer un LOOP y asignar los valores de la tabla T_PROGRAMAS a la tabla T_PROGRAMAS_AUX. ID_PROG TYPE ZPROGRAMAS-ID_PROG. T_PROGRAMAS_AUX TYPE STANDARD TABLE 107 . Eso está bien para algunos campos. MOVE <FS_PROGRAMAS>-NOM_PROG TO <FS_PROGRAMAS_AUX>-NOM_PROG. por lo cual no podemos seguir utilizando el []. ID_PROG TYPE ZPROGRAMAS-ID_PROG. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. con lo cual hacemos que ambas tablas internas sean distintas...Entonces debemos utilizar una forma alternativa. pero si tenemos por decir 20 campos. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. TYPES: BEGIN OF TY_PROGRAMAS_AUX.ASSIGNING <FS_PROGRAMAS_AUX>. ID TYPE ZPROGRAMAS-ID. END OF TY_PROGRAMAS. MOVE <FS_PROGRAMAS>-ID_PROG TO <FS_PROGRAMAS_AUX>-ID_PROG. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. MOVE-CORRESPONDING <FS_PROGRAMAS> TO <FS_PROGRAMAS_AUX>. APPEND INITIAL LINE TO T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. 108 . ya se solamente tenemos una forma de hacerlo.OF TY_PROGRAMAS_AUX. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. Ordenar tablas internas Esto es bastante simple. ENDLOOP. 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. Cuando utilizamos el MOVE-CORRESPONDING. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. ID_PROG TYPE ZPROGRAMAS-ID_PROG. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. END OF TY_PROGRAMAS. 109 . 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). NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. SORT T_PROGRAMAS BY ID_PROG ASCENDING. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. Utilizamos la sentencia SORT para ordenar una tabla interna.TYPES: BEGIN OF TY_PROGRAMAS. SORT T_PROGRAMAS BY ID_PROG DESCENDING. <FS_PROGRAMAS>-ID_PROG = '006'. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. <FS_PROGRAMAS>-ID_PROG = '005'. 110 . DATA: VAR TYPE I. DO. WRITE:/ VAR. ELSE. VAR = VAR + 1. WHILE VAR LT 10. WRITE:/ VAR. IF VAR LT 10. ENDWHILE. imprimimos el valor. ENDIF. VAR = VAR + 1. Aumentamos el valor de VAR de uno en uno.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. podemos utilizar un LOOP para recorrer todos los registros de una tabla interna. ENDDO. por cada vuelta del WHILE. EXIT. DATA: VAR TYPE I. Esto significa que mientras la variable VAR sea menor o igual a 10. También tenemos presente el DO-ENDO. En el caso afirmativo imprimimos y aumentamos en uno. le decimos al DO-ENDO que solo realice el bucle 10 veces. también podríamos haberlo escrito así: DATA: VAR TYPE I. o por lo menos no tanto como otros lenguajes (Como por 111 . 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. Utilizando un IF preguntamos si el valor de la variable es menor o igual a 10. Adicionalmente tenemos los comandos CONTINUE y EXIT. Aunque. DO 10 TIMES. Imprimimos el valor de la variable VAR y la aumentamos en uno. Cuando VAR es mayor a 10. En esta caso. Trabajando con Cadenas de Texto Si bien el ABAP no está diseñado para trabajar con cadenas de texto. salimos del DO-ENDDO utilizando un EXIT. ENDDO. VAR = VAR + 1.El DO-ENDDO es un bucle repetitivo que avanza mientras no le digamos que tiene que salir. WRITE:/ VAR. 112 . une cadenas en una cadena más grande.ejemplo PERL). Con TO UPPER CASE convertimos a Mayúsculas y con TO LOWER CASE convertimos a Minúsculas. WRITE:/ VAR. DATA: VAR TYPE STRING. TRANSLATE VAR TO LOWER CASE. VAR = 'El Arte de Programar'. • CONCATENATE Concatena dos o más cadenas de texto. Es decir. TRANSLATE VAR TO UPPER CASE. VAR_TEXT TYPE STRING. VAR_AUX TYPE STRING. DATA: VAR TYPE STRING. WRITE:/ VAR. de todos modos nos brinda alguna poderosas herramientas como estas: • TRANSLATE Convierte una cadena de texto a Mayúsculas o Minúsculas. VAR_TEXT TYPE STRING. esto lo arreglamos fácilmente. VAR = 'El Arte de Programar'. DATA: VAR TYPE STRING. Con el CONCATENATE decimos que los valores de las variables VAR y VAR_AUX se guarden en la variable VAR_TEXT.VAR = 'El Arte de Programar'. Simplemente agregamos un SEPARATED BY al final del CONCATENATE. CONCATENATE VAR VAR_AUX INTO VAR_TEXT SEPARATED BY SPACE. VAR_AUX TYPE STRING. Aunque claro. WRITE:/ VAR_TEXT. en este caso al utilizar SPACE le 113 . WRITE:/ VAR_TEXT. VAR_AUX = 'SAP NETWEAVER'. si ejecutamos el programa nos daremos cuenta de que no hay ningún espacio entre las dos palabras. CONCATENATE VAR VAR_AUX INTO VAR_TEXT. VAR_AUX = 'SAP NETWEAVER'. 114 . END OF TY_CADENAS. VAR_TEXT = 'SAP NETWEAVER'.estamos diciendo que separe el texto con un espacio en blanco. SPLIT VAR_TEXT AT SPACE INTO VAR VAR_TEXT. DATA: VAR TYPE STRING. 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. WRITE:/ VAR. WRITE:/ VAR_TEXT. VAR_AUX TYPE STRING. VAR(30) TYPE C. DATA: T_CADENAS TYPE STANDARD TABLE OF TY_CADENAS. VAR_TEXT TYPE STRING. dependiendo de un carácter aguja. TYPES: BEGIN OF TY_CADENAS. Declaramos una variable de tipo STRING y utilizando el SPLIT mandamos las subcadenas a la tabla interna. • SHIFT Utilizado con la sentencia DELETING. SPLIT VAR_TEXT AT SPACE INTO TABLE T_CADENAS. Creamos un tipo de tabla con un campo llamado VAR de tipo C y longitud 30. Creamos una tabla interna con referencia a nuestro tipo de tabla. VAR_TEXT = ' SAP NETWEAVER '. permite eliminar los espacios o caracteres al inicio o al final de una cadena de texto. SHIFT VAR_TEXT RIGHT DELETING TRAILING SPACE.DATA: VAR_TEXT TYPE STRING. DATA: VAR_TEXT TYPE STRING. 115 . La variable VAR_TEXT tiene cinco espacios al inicio y cinco espacios al final del texto. SHIFT VAR_TEXT LEFT DELETING LEADING SPACE. Utilizando el SHIFT LEFT DELETING LEADING eliminamos los espacios en blanco del inicio de la cadena. VAR_TEXT = 'SAP NETWEAVER'. CONDENSE VAR_TEXT. • REPLACE Reemplaza una cadena por otra. Con el CONDENSE eliminamos todos los espacios de la cadena. DATA: VAR_TEXT TYPE STRING.Utilizando el SHIFT RIGHT DELETING TRAILING eliminamos los espacios en blanco del final de la cadena. REPLACE SPACE WITH '/' INTO VAR_TEXT. Con el CONDESE eliminamos los espacios del inicio y del final de la cadena. pero toma los espacios del final y del inicio al mismo tiempo. 116 . CONDENSE VAR_TEXT NO-GAPS. VAR_TEXT = ' SAP NETWEAVER '. • CONDENSE Elimina los espacios en blanco. DATA: VAR_TEXT TYPE STRING. como lo hace el SHIFT. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'. queremos que busque todas las ocurrencia de “/” y la reemplace con un espacio.VAR_TEXT = 'SAP/NETWEAVER/PROGRAMMING'. • FIND Busca una subcadena en una cadena. Porque? Realmente no lo sé. REPLACE ALL OCCURRENCES OF '/' IN VAR_TEXT WITH SPACE . Con REPLACE decimos que reemplace el espacio en blanco con el caracter “/”.. DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. Aunque solamente va a buscar y reemplazar la primera ocurrencia del espacio. Si hubiéramos dicho que busque las ocurrencia del espacio y las reemplace por un “/”. pero lamentablemente no pudimos hallar una respuesta adecuada. 117 . FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'.Tuvimos una emocionante discusión en el SDN (SAP Developer Network) acerca de esto. DATA: VAR_TEXT TYPE STRING.. En el segundo caso. nuestro programa había fallado miserablemente. DATA: VAR_TEXT TYPE STRING. ENDIF. Cuando utilizamos el FIND para hacer la búsqueda de la subcadena.FIND 'NETWEAVER' IN VAR_TEXT RESULTS RESULT_TAB. debemos asignar el resultado a la tabla interna RESULT_TAB y de ella leer la posición de la subcadena dentro de la cadena. deberíamos hacer lo siguiente: DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. 118 . FIND ALL OCCURRENCES OF 'SAP' IN VAR_TEXT RESULTS RESULT_TAB. Creamos una tabla interna llamada RESULT_TAB de tipo MATCH_RESULT_TAB (Que es un tipo predefinido en ABAP). IF SY-SUBRC EQ 0. FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. WRITE:/ <FS_RESULT>-OFFSET. IF SY-SUBRC EQ 0. Si quisiéramos encontrar todas la ocurrencias de la cadena. READ TABLE RESULT_TAB INDEX 1 ASSIGNING <FS_RESULT>. VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. Incluyendo el ALL OCCURRENCES OF podemos conocer todas las ocurrencias de una subcadena dentro de una cadena. ENDLOOP. 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. LONG TYPE I. • STRLEN Obtiene la longitud de una cadena. LONG = STRLEN( VAR_TEXT ). DATA: VAR_TEXT TYPE STRING. Utilizando STRLEN podemos conocer la longitud en caracteres de una cadena de texto. WRITE:/ <FS_RESULT>-OFFSET.LOOP AT RESULT_TAB ASSIGNING <FS_RESULT>. VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. • SY-TABIX Dentro de un LOOP. (Todas pueden ser encontradas en la tabla SYST). nos indica el número de “vuelta” o iteración o el índice del registro que estamos leyendo. • SY-LANGU Idioma de trabajo actual. 120 . determina el número de página en la cual nos encontramos. No ha podido ejecutarse.sistema. SY-SUBRC = 0 SY-SUBRC = 4 • SY-PAGNO En un reporte de tipo listado. Error. Veamos cuales son las más importantes. • SY-MANDT Ejecutado con éxito. • SY-SUBRC Retorna un valor que determina el estado de las operaciones en ABAP. • SY-BACTH Nos indica si el programa se está ejecutando en fondo o en modo directo. • SY-DATUM Fecha actual del sistema. • SY-UNAME Nombre del usuario logeado en el sistema.Nos indica el número de mandante en el cual estamos trabajando. debemos utilizar funciones para poder modularizarlos. • SY-UZEIT Hora actual del sistema. • 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. • SY-REPID Nombre del programa que estamos creando o ejecutando. Modularización de Programas Para que nuestros programas sean más fáciles de mantener y de programas. 121 . *=====================================================* * DECLARACION DE TABLES TABLES: ZPROGRAMAS. Para entender mejor a que nos referimos. vamos a hacer un ejemplo. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. * *=====================================================* * *=====================================================* 122 .Las funciones tienen el siguiente formato: FORM XXX USING YYY CHANGING YYY TABLES YYY. … ENDFORM. Y se llaman así: PERFORM XXX USING YYY CHANGING YYY TABLE YYY. *=====================================================* * DECLARACION DE VARIABLES DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. PERFORM OBTENER_DATOS. END OF TY_PROGRAMAS. *=====================================================* * FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. PERFORM MOSTRAR_REPORTE. SELECTION-SCREEN END OF BLOCK PRG. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 123 .ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ENDLOOP.*&----------------------------------------------------* *& Form obtener_datos * *&----------------------------------------------------* FORM OBTENER_DATOS. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. "MOSTRAR_REPORTE Se darán cuenta de que este es el mismo ejemplo que ya habíamos desarrollado. <FS_PROGRAMAS>-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. "obtener_datos *&----------------------------------------------------* *& Form MOSTRAR_REPORTE * *&----------------------------------------------------* FORM MOSTRAR_REPORTE. WRITE:/ SY-ULINE(45). lo hemos modularizado. WRITE:/ <FS_PROGRAMAS>-NOMBRE. 124 .33 'Programa'.17 'Entorno'. ENDFORM. aunque ahora. WRITE:/1 'Lenguaje'. <FS_PROGRAMAS>-NOM_PROG. ENDFORM. Ahora. FORM OBTENER_DATOS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. llamamos a nuestras dos funciones OBTENER_DATOS y MOSTRAR_REPORTE. "obtener_datos En este caso. Aunque de todos modos. 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. Luego del START-OF-SELECTION. ENDFORM. veamos un ejemplo que utilice las características de los FORMS. PERFORM OBTENER_DATOS.START-OF-SELECTION. *=====================================================* * START-OF-SELECTION * * *=====================================================* 125 . nos ayuda a tener un código más ordenado. *=====================================================* * DECLARACION DE VARIABLES DATA: VAR TYPE STRING. las funciones o FORM no hacen más que encapsular las funcionalidades que habíamos desarrollado anteriormente. PERFORM MOSTRAR_REPORTE. TRANSLATE P_VAR TO UPPER CASE. PERFORM CONVERTIR USING 'U' CHANGING VAR. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. ENDFORM. ENDFORM. ENDCASE. WHEN 'U'.*=====================================================* START-OF-SELECTION. WRITE:/ VAR. "CONVERTIR 126 . WRITE:/ VAR. PERFORM CONVERTIR USING 'L' CHANGING VAR. WHEN 'L'. CASE P_TIPO. PERFORM INICIALIZAR. TRANSLATE P_VAR TO LOWER CASE. VAR = 'El Arte de Programar NETWEAVER'. "INICIALIZAR *&----------------------------------------------------* *& Form CONVERTIR * *&----------------------------------------------------* FORM CONVERTIR USING P_TIPO CHANGING P_VAR. tenemos dos FORMS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. Luego de llamar a cada PERFORM. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS.En este caso. 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. si es L (Lower). *=====================================================* * *=====================================================* * *=====================================================* 127 . utilizamos un CASE-ENDCASE para poder determinar el valor del parámetro P_TIPO. imprimimos el valor de P_VAR. entonces hacemos un TRANSLATE TO UPPER CASE y cambiamos el valor de P_VAR. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. En el caso de ser U (Upper). Dentro del FORM CONVERTIR. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. END OF TY_PROGRAMAS. hacemos un TRANSLATE TO LOWER CASE y cambiamos el valor de P_VAR. En caso contrario. PERFORM IMPRIMIR_REPORTE TABLES T_PROGRAMAS. <FS_PROGRAMAS>-NOM_PROG = 'POKEMON'. <FS_PROGRAMAS>-ID_PROG = '001'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-NOM_PROG = 'TETRIS'. ENDFORM. * *=====================================================* *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM INICIALIZAR. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. " inicializar * *=====================================================* *&----------------------------------------------------* *& Form IMPRIMIR_REPORTE * *&----------------------------------------------------* FORM IMPRIMIR_REPORTE TABLES T_TABLA.* DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. *&----------------------------------------------------* *& Form inicializar * *&----------------------------------------------------* FORM INICIALIZAR. LOOP AT T_TABLA 128 . <FS_PROGRAMAS>-ID_PROG = '002'. 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) Execute (F6) Return (F7) Ejecuta una línea de código. Ejecuta un bloque de código. Sale de un bloque de código. Continua con la ejecución del programa Run (to Cursor) (F8) 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 BreakPoint 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 140 . EXPONENTE = EXPONENTE * 10. WRITE / 'Error de cálculo'. SUMA = SUMA + DIGITO * EXPONENTE. ENDWHILE. ENDCATCH. DIGITO = NUMERO MOD 2. IF SY-SUBRC = 5. ENDFORM. CONDENSE P_SUM NO-GAPS. WHILE NUMERO GT 0. ENDIF. P_SUM = SUMA.25 P_NUMERO. ENDFORM.CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. " CALCULAR_BINARIO *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. NUMERO = NUMERO DIV 2.5 SUMA_TEXT. WRITE:/ 'es:'. e incluye un elemento muy interesante. " IMPRIMIR Este programa convierte un número decimal a binario. WRITE:/ 'El número binario de'. el CATCH. FLAG = 'X'. WHILE NUMERO GT 0.CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. Y además utilizamos una variable FLAG a la cual se le pasa el valor X. ENDWHILE. ENDIF. FLAG = 'X'. comprobamos el valor de esta variable para no imprimir si es que ha habido errores. mostramos un mensaje de error. Como podemos ver. P_SUM = SUMA. 141 . ENDCATCH. NUMERO = NUMERO DIV 2. DIGITO = NUMERO MOD 2. CONDENSE P_SUM NO-GAPS. EXPONENTE = EXPONENTE * 10. por lo tanto: IF SY-SUBRC = 5. SUMA = SUMA + DIGITO * EXPONENTE. En este caso. lo que queremos es que el ABAP capture cualquier error de tipo aritmético. Antes de imprimir. por lo tanto utilizamos ARITHMETIC_ERRORS. WRITE / 'Error de cálculo'. el código que convierte el decimal a un binario está encerrado entre las sentencias CATCH-ENDCATCH. Si hay algún error el valor 5 se pasa a la variable del sistema SYSUBRC. Si SY-SUBRC es igual a 5. PERFORM IMPRIMIR. ENDIF. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. * *=====================================================* 142 .IF FLAG EQ SPACE. *=====================================================* * DECLARACION DE VARIABLES DATA: I TYPE I. Colores en ABAP Este programa muestra las posibles combinaciones de colores que pueden generarse en ABAP. WHEN 5. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. COL = 'COL_BACKGROUND '. COL = 'COL_POSITIVE '. COL = 'COL_NORMAL '. WHEN 4. * *=====================================================* 143 . WHEN 7. SKIP 2. AT 7 SY-VLINE. COL = 'COL_KEY '. ENDCASE. WRITE: /(4) I. COL = 'COL_GROUP '. COL = 'COL_TOTAL '. CASE I. 48 'INVERSE'. WHEN 3. WRITE:/9 'INTESIFIED ON'. FORMAT INTENSIFIED COLOR = I. WHEN 2. SY-VLINE. COL = 'COL_NEGATIVE '. WHILE I < 8. COL. 27 'INTENSIFIED OFF'. WHEN 6. COL = 'COL_HEADING '. PERFORM IMPRIMIR.COL(15) TYPE C. WHEN 1. WHEN 0. *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. SY-VLINE. " IMPRIMIR Lenguajes y Programas REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TYPES * *=====================================================* * *=====================================================* 144 .COL INTENSIFIED OFF. COL INVERSE. I = I + 1. ENDWHILE. ENDFORM. *=====================================================* * DECLARACION DE INCLUDES INCLUDE <ICON>. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *&----------------------------------------------------* *& Form SELECCIONAR_DATOS * *&----------------------------------------------------* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 145 . *=====================================================* * DECLARACION DE VARIABLES DATA: ICONO TYPE STRING. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. PERFORM SELECCIONAR_DATOS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. *=====================================================* * START-OF-SELECTION START-OF-SELECTION.TYPES: BEGIN OF TY_PROGRAMAS. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. PERFORM IMPRIMIR_DATOS. END OF TY_PROGRAMAS. 15 <FS_PROGRAMAS>-ENTORNO. ENDFORM. FORMAT COLOR 5. WHEN 'SCRIPT'. 25 'Programa'. ICONO = ICON_WD_WEB_PROJECT. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. 146 . 40 'Icono'. SKIP 1. WHEN 'WEB'.15 'Entorno'. WRITE:/1 <FS_PROGRAMAS>-NOMBRE. ICONO = ICON_FOLDER. CASE <FS_PROGRAMAS>-ENTORNO. ICONO = ICON_HISTORY. " SELECCIONAR_DATOS *&----------------------------------------------------* *& Form IMPRIMIR_DATOS * *&----------------------------------------------------* FORM IMPRIMIR_DATOS. FORMAT COLOR OFF. 25 <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 ). WRITE:/1 'Lenguaje'. WHEN 'DESKTOP'.FORM SELECCIONAR_DATOS. debemos incluir un subprograma llamado <ICON> con la palabra reservada INCLUDE. 15 <FS_PROGRAMAS>-ENTORNO. " IMPRIMIR_DATOS Este programa es muy parecido al que hicimos alguna páginas antes. ENDLOOP. 25 <FS_PROGRAMAS>-NOM_PROG. ICONO = ICON_WD_WEB_PROJECT. ENDLOOP. WHEN 'WEB'. Para esto. ENDFORM. de estamos mostrando un icono que representa a cada tipo de lenguaje. ENDCASE. WRITE:/1 <FS_PROGRAMAS>-NOMBRE. CASE <FS_PROGRAMAS>-ENTORNO. podemos llamar a cualquier icono de la tabla ICON. ICONO = ICON_HISTORY. a la cual vamos a asignarle las constantes de iconos que obtenemos de la tabla ICON (Campo Name). WRITE: 40 ICONO. WHEN 'DESKTOP'. con la particularidad. ICONO = ICON_FOLDER. WRITE: 40 ICONO.ENDCASE. Gracias a este include. Simplemente utilizando un CASE- 147 . LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WHEN 'SCRIPT'. Declaramos una variable de tipo STRING llamada ICONO. ENDCASE sabemos que valores asignar a la variable ICON para luego simplemente imprimirlo. 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). *=====================================================* * DECLARACION DE TYPES TYPES: X_LINES TYPE STRING. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* * *=====================================================* 148 . REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. PERFORM IMPRIMIR USING TEXTO. *=====================================================* * DECLARACION DE VARIABLES DATA: TEXTO(30) TYPE C. PERFORM FILL_RIGHT_CHARACTERS USING '*' CHANGING TEXTO. V_LONG TYPE I. SELECTION-SCREEN END OF BLOCK DEC_TO_BIN. * *=====================================================* * *=====================================================* * *=====================================================* 149 . PARAMETERS: P_TEXTO(20) TYPE C.DATA: T_TABLE TYPE STANDARD TABLE OF X_LINES. AUX_TEXT(30) TYPE C. PERFORM INICIALIZAR. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. V_LEN TYPE I. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK DEC_TO_BIN WITH FRAME. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_TABLE> LIKE LINE OF T_TABLE. PERFORM IMPRIMIR_TABLA TABLES T_TABLE. "INICIALIZAR *&----------------------------------------------------* *& Form IMPRIMIR_TABLA * *&----------------------------------------------------* FORM IMPRIMIR_TABLA TABLES T_TAB. PERFORM SPLIT_LONG_TEXT TABLES T_TABLE USING TEXTO. PERFORM INICIALIZAR. 150 . PERFORM INICIALIZAR. SKIP 1. PERFORM IMPRIMIR USING TEXTO. PERFORM CAPITALIZE_LETTERS CHANGING TEXTO. PERFORM IMPRIMIR USING TEXTO. ENDFORM. TEXTO = P_TEXTO.PERFORM INICIALIZAR. PERFORM REVERSE_STRING USING TEXTO. WRITE:/ <FS_TABLE>. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. LOOP AT T_TAB ASSIGNING <FS_TABLE>. "imprimir *&----------------------------------------------------* *& * Form FILL_RIGHT_CHARACTERS * *&----------------------------------------------------* Llena una cadena con caracteres a la derecha. V_LEN = V_LONG . WRITE:/ TEXTO. V_LEN = STRLEN( L_TEXTO ). "FILL_RIGHT_CHARACTERS 151 . DO V_LEN TIMES. DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE. * *-----------------------------------------------------* FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. *& Form imprimir "INICIALIZAR * *&----------------------------------------------------* *&----------------------------------------------------* FORM IMPRIMIR USING L_TEXTO. ENDFORM. ENDDO.ENDLOOP. ENDFORM.V_LEN. CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. ENDFORM. V_LONG = V_LONG . "CAPITALIZE_LETTERS 152 . AUX_TEXT = <FS_TABLE>+0(1). TRANSLATE L_TEXTO TO LOWER CASE. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE.*&----------------------------------------------------* *& * Form CAPITALIZE_LETTERS * * *&----------------------------------------------------* Capitaliza un texto dado. CLEAR L_TEXTO.1. ENDFORM. SHIFT L_TEXTO LEFT DELETING LEADING SPACE. TRANSLATE AUX_TEXT TO UPPER CASE. *-----------------------------------------------------* FORM CAPITALIZE_LETTERS CHANGING L_TEXTO. LOOP AT T_TABLE ASSIGNING <FS_TABLE>. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. V_LONG = STRLEN( <FS_TABLE> ). CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. ENDLOOP. "SPLIT_LONG_TEXT 153 . ENDFORM. = T_TAB = L_TEXTO = SPACE DESCRIBE TABLE T_TAB LINES V_LEN. CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE DELIMITER TABLES OUT_LINES EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. DELETE T_TAB INDEX V_LEN.*&----------------------------------------------------* *& * * Form SPLIT_LONG_TEXT * * * *&----------------------------------------------------* Corta un texto largo en varios registros de una tabla *-----------------------------------------------------* FORM SPLIT_LONG_TEXT TABLES T_TAB USING L_TEXTO. "REVERSE_STRING = L_TEXTO = L_TEXTO = SY-LANGU En este programa tenemos varios FORMS y cada uno realiza una tarea en particular. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING LANG IMPORTING RSTRING EXCEPTIONS TOO_SMALL = 1 OTHERS ENDFORM. = 2. Veamos cada uno de ellos. 154 . FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE. V_LEN = STRLEN( L_TEXTO ).*&----------------------------------------------------* *& * Form REVERSE_STRING * * *&----------------------------------------------------* Invierte una cadena *-----------------------------------------------------* FORM REVERSE_STRING CHANGING L_TEXTO. LOOP AT T_TABLE ASSIGNING <FS_TABLE>. ENDDO. CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. en este caso el ‘*’. 155 . Utizamos un DO para ejecutar un bucle un número V_LEN de veces y concatenamos el texto con el carácter de relleno. FORM CAPITALIZE_LETTERS CHANGING L_TEXTO. la longitud con espacios menos la longitud sin espacios.V_LEN = V_LONG . CLEAR L_TEXTO. TRANSLATE L_TEXTO TO LOWER CASE. restamos la longitud de V_LONG menos V_LEN. En la variable V_LEN. es decir. DO V_LEN TIMES. Y luego utilizamos DESCRIBE FIELD LENGTH IN CHARACTER MODE para determinar la longitud pero sin contar los espacios en blanco. "FILL_RIGHT_CHARACTERS Utilizamos STRLEN para determinar la longitud total del texto (Incluyendo espacios en blanco). V_LONG = STRLEN( <FS_TABLE> ).V_LEN. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. ENDFORM. Leemos el primer carácter utilizando +0(1) que significa. Concatenamos el primer caracter mas los demás caracteres de la cadena.V_LONG = V_LONG . enviamos las subcadenas a una tabla interna. FORM SPLIT_LONG_TEXT TABLES T_TAB USING L_TEXTO. leer un caracter empezando desde la primera posición. AUX_TEXT = <FS_TABLE>+0(1). CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. Luego con un SPLIT AT SPACE INTO TABLE. ENDLOOP. Utilizando TRANSLATE TO UPPER CASE.1. SHIFT L_TEXTO LEFT DELETING LEADING SPACE. ENDFORM. para poder modificarlos uno por uno. convertimos a Mayúsculas el caracter que hemos leído. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE. "CAPITALIZE_LETTERS Primero. Finalmente concatenamos todos las subcadenas en una cadena más grande con los letras ya capitalizadas. 156 . TRANSLATE AUX_TEXT TO UPPER CASE. Con STRLEN determinamos la longitud del Field-Symbol y le restamos uno. convertimos la cadena a Minúsculas utilizando el TRANSLATE TO LOWER CASE. "SPLIT_LONG_TEXT Utilizamos la función RSDG_WORD_WRAP para partir una cadena en subcadenas y enviarlas a una tabla. Al final. DELETE T_TAB INDEX V_LEN. ENDFORM. pero quería que vieran como se utilizan los módulos de funciones.CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE DELIMITER TABLES OUT_LINES EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. Podríamos haber utilizado un SPLIT INTO TABLE. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING = L_TEXTO 157 . podemos eliminar la última sin tener problemas. El módulo de funciones que utilizamos tiende a tomar los espacios en blanco y agregarlos como longitud total de la cadena. utilizando un DESCRIBE TABLE LINES para poder determinar cuantas líneas tiene nuestra tabla interna. es por eso que sabiendo cuantas líneas tienen la tabla interna. = T_TAB = L_TEXTO = SPACE DESCRIBE TABLE T_TAB LINES V_LEN. FORM REVERSE_STRING CHANGING L_TEXTO. LANG IMPORTING RSTRING EXCEPTIONS = SY-LANGU = L_TEXTO TOO_SMALL = 1 OTHERS ENDFORM. 158 . "REVERSE_STRING Utilizamos el módulo de funciones STRING_REVERSE para invertir el orden de la cadena. = 2. Facturas. para Certificados de Trabajo.SapScript Introducción Uno de los puntos fuertes que tiene el ABAP. debemos ingresar a la transacción SE71 (Form Painter). aunque lo último depende más que nada de la impresora o de software adicional para poder mostrarlos correctamente. Su creación no es complicada y permite hacer varias cosas interesantes. Como por ejemplo. incluir logos o imprimir códigos de barras. Creando un formulario Para poder crear formularios. etc. que pueden ser utilizados por ejemplo. Notificaciones de Empresa. es la posibilidad de crear formularios. 159 . puesto que solamente permite Alemán e Inglés..En el campo formulario..La versión completa del NetWeaver incluye entre muchos otros. Presionamos el botón Create (Crear) crear nuestro formulario. Francés. puede hacerlo con muchos idiomas predefinidos (Bueno. En realidad.. no esta versión. puesto que cuando uno ingresa a NetWeaver. Italiano.. el idioma se utiliza para poder crear de una manera más sencilla las traducciones. Español. el idioma en el cual queremos crearlo (Bastante simple no?).). para poder 160 . ingresamos el nombre de nuestro formulario y en el campo idioma. Luego de esto. deberemos ingresar un texto que describa brevemente al formulario. deberemos ingresar a la sección de Basic Settings (Parametrizaciones Básicas) con el siguiente botón . 161 .En esta ventana. necesitamos crear un nuevo elemento. Como vemos. no existe ninguna página.En esta ventana. Esto podemos hacerlo de 3 162 . Para poder crearla.. ninguno de estos existe. 1. Como este formulario es nuevo. se nos exige especificar una Página Inicial y un Párrafo por defecto. por lo cual deberemos crearlos. presionando el siguiente botón .Crear una página inicial Ingresamos a la opción Pages (Páginas). Con un clic derecho. 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. una descripción de la página. podremos verlo como se muestra a continuación. Por convención. 164 . Y un formulario puede tener muchas páginas.Crear una ventana en una página Después de haber creado nuestra página. que es el espacio en el cual vamos a trabajar para poder crear nuestros formularios.En Page (Página) ingresaremos el nombre de la página que queremos crear y en Description (Description).. Para poder crear una ventana. Una página puede tener muchas ventanas. deberemos hacer clic en el botón Page Windows (Ventanas de Página) . simpre la página principal será llamada MAIN. 2. deberemos asignarle una ventana. Luego de haber creado el elemento. Cuando creamos el nuevo elemento.Y seguir un procedimiento similar al de la creación de la página. 165 . creada cuando creamos la página. Es decir. En esta ventana. se nos muestra una ventana por defecto. se nos muestra la siguiente ventana. Si queremos crear ventanas adicionales. deberemos de crear un nuevo elemento. Por cada Ventana Página que creemos. tenemos disponibles los siguientes sistemas de medición. deberemos llenar sus atributos en la siguiente ventana (Que está al final de la pantalla). Por ejemplo: Para poder definir las propiedades de las ventanas.deberemos hacer clic en el botón Windows (Ventanas) crear un nuevo elemento. y Para poder elegir la ventana. 166 . simplemente deberemos de hacer un doble clic sobre ella. 3. 167 .Crear párrafo por defecto Para crear un nuevo párrafo. ). los tabuladores (Con el botón Tabs su asignación (Con el botón Outline ). etc. Aquí deberemos asignarle un nombre al nuevo párrafo (Por convención utilizamos ST). deberemos hacer clic en el botón Paragraph Formats (Formatos de Párrafo) Se nos mostrará la siguiente ventana: . así como el tipo de letra (Con el botón Font ).. Una vez que hemos creado la página y el párrafo por defecto. 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) F5. Y luego en el botón o presionamos básicas parametrizaciones . Para esto. 168 . Es importante indicar cual es la página principal. * *=====================================================* 169 . debemos grabar el formulario y activarlo mediante el menú. Es por eso. que vamos a crear un programa bastante sencillo para utilizar como ejemplo.ITCPP.TOA_DARA. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. esta debe provenir de un programa. Este programa llama al formulario y le pasa toda la información necesaria.ITCPO. Creando un programa de impresión Para que un SAPScript pueda mostrar información.Una vez que hemos terminado. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_ZPROGRAMAS. V_SCRIPT. SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 170 . *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. *=====================================================* * START-OF-SELECTION START-OF-SELECTION.*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. PERFORM INICIALIZAR. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * DECLARACION DE VARIABLES DATA: V_FORM(14) TYPE C. "INICIALIZAR * *=====================================================* *&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SAPSCRIPT. ITCPO-TDPREVIEW = 'X'. ENDFORM. IF V_SCRIPT EQ SPACE. ITCPO-TDLIFETIME = '7'. CALL FUNCTION 'OPEN_FORM' EXPORTING 171 . ITCPO-TDIMMED = '*'. PERFORM ABRIR_SAPSCRIPT.*=====================================================* * END-OF-SELECTION END-OF-SELECTION. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. V_FORM = 'ZDUMMY_FORM'. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG. ITCPO-TDDELETE = '*'. V_SCRIPT = 'X'. = 'MAIN' 172 . EXIT. ENDIF. ARCHIVE_INDEX = TOA_DARA CALL FUNCTION 'START_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S'. CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. = V_FORM = 'S' = ITCPO = 'PRINTER' = 'X' = 01. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'MAIN' WINDOW EXCEPTIONS OTHERS ENDLOOP.FORM LANGUAGE OPTIONS DEVICE DIALOG EXCEPTIONS CANCELED IF SY-SUBRC NE 0. = 01. LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. ENDIF. 173 .ITCPO. ITCPO-TDDELETE = '*'.TOA_DARA. V_SCRIPT. ENDIF. Las tablas ITCPO. Parámetro impresión. borrar tras salida.ITCPP. La variable V_FORM contendrá el nombre del formulario. • • • Parámetro impresión. tiempo de permanencia en SPOOL. Parámetro impresión.IF V_SCRIPT NE SPACE. ITCPO-TDPREVIEW = 'X'. ITCPO-TDLIFETIME = '7'. TOA_DARA y ITCPP son necesarias para poder ejecutar el SAPScript. CALL FUNCTION 'CLOSE_FORM'. salida inmediata. mientras que la variable V_SCRIPT nos sirve para determinar si el formulario está activo o no. ITCPO-TDIMMED = '*'. DATA: V_FORM(14) TYPE C. TABLES: ZPROGRAMAS. ENDFORM. "ABRIR_SAPSCRIPT Analicemos un poco el programa. para OPEN_FORM. esto utilizamos el módulo de funciones CALL FUNCTION 'START_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S'. EXIT.• Visualización de impresión. = 01. = V_FORM = 'S' = ITCPO = 'PRINTER' = 'X' IF V_SCRIPT EQ SPACE. entonces debemos abrir el formulario. CALL FUNCTION 'OPEN_FORM' EXPORTING FORM LANGUAGE OPTIONS DEVICE DIALOG EXCEPTIONS CANCELED IF SY-SUBRC NE 0. Si la variable V_SCRIPT está vacía. 174 . ARCHIVE_INDEX = TOA_DARA ENDIF. ENDIF. V_SCRIPT = 'X'. Iniciamos la ejecución del formulario. Por cada vuelta del LOOP. 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.LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW EXCEPTIONS OTHERS ENDLOOP. CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. Con el módulo de funciones END_FORM indicamos que hemos terminado de utilizar la ventana. = 01. CALL FUNCTION 'CLOSE_FORM'. 175 . ENDIF. IF V_SCRIPT NE SPACE. = 'MAIN' Hacemos un LOOP a la tabla interna T_ZPROGRAMAS y asignamos los valores al Field-Symbol <FS_PROGRAMAS>. cerramos el formulario con el módulo de funciones CLOSE_FORM. Simplemente. debemos marcar el check Graphical Form Painter (Form Painter gráfico). Debemos ingresar al menú Settings (Opciones) y presionar Form Painter. podemos regresar a nuestro formulario para poder comenzar a llenar los datos que queremos mostrar cuando sea ejecutado. 176 . Para poder acceder. Diseñando el formulario Además de la forma que ya vimos para crear nuestro formulario.Una vez creado el programa. deberemos ingresar a la transacción SE71 (Form Painter). contamos con un editor gráfico. En este editor gráfico. deberemos presionar el botón Text (Texto) . Para poder asignar el código a la ventana. simplemente debemos desmarcar el checkbox de Form Painter gráfico. Para volver al modo de edición por defecto. podemos especificar el tamaño y la disposición de las distintas ventanas que creemos en nuestro formulario. 177 .Ingresamos a nuestro formulario y presionamos el botón Layout (Diposición) . Como podemos ver. a los campos de la tabla interna) y mostrarlos al momento de imprimir el formulario. veremos que hemos escrito texto y el nombre de los campos del field-symbol dentro de ampersands (&). En la parte de código. podremos escribir el código para llamar a los campos que definimos en nuestro programa (Es decir.En esta ventana. o llamandolo explicítamente como ST Párrafo por defecto. Si los 178 . dejando el menú por defecto. podemos llamar al tipo de párrafo por defecto de dos maneras. Una vez ahí. Primero que nada. 179 . Supongamos que queremos que los textos se muestren en negrita y los valores como un texto normal. Ahora. haremos lo siguiente. 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. hacemos clic en Character Formats (Formatos de Caracter) . no podríamos llamar a las variables de nuestro programa dentro del formulario.ampersand. debemos grabar nuestro código y retroceder con el botón BACK (Retroceder) o presionar F3. Seleccionamos el texto que queremos en negrita. puesto que debemos crear la caja utilizando código. Y de paso eliminamos cualquier código adicional que haya agreagado el SAPScript. 180 . vamos a crear una caja para que se muestre el nombre del programa. Para esto.Para terminar. debemos cambiar de editor. (Yo recomiendo siempre utilizar este editor). Una ventana se puede llamar una sola vez. puesto que al tratarse de un formulario. que tenga 50 milimetros de ancho y 5 de alto. varias veces. Se habrán dado cuenta. pero un elemento. Grabamos. Al momento de ejecutar el programa. se nos muestra una ventana de impresión. y que el borde sea de 10 TW.Creamos una caja que empieza en la posición 0. de que además agregamos la línea /E ITEM Puesto que ITEM va a ser nuestro ELEMENTO dentro del ventana. Elegimos LP01 como impresora por defecto y presionamos Print Preview (Vista previa de 181 . activamos y ejecutamos nuestro programa. debemos imprimirlo para poder visualizarlo. es decir indicamos cual va a ser la posición Y de la caja. En el editor. Puesto que no queremos imprimirlo. 182 . sino simplemente comprobar que está bien hecho el formulario. En este caso. pero los textos están muy juntos los unos de los otros. Los datos son correctos.impresión). 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&. agregamos YPOS &POS& MM. 183 . LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. = 'MAIN' En cada iteración del LOOP.Además. debemo también agregar algunas cosas en el programa. = 01. POS TYPE STRING. agregamos una línea en blanco. ya podemos imprimir nuevamente el formulario. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW EXCEPTIONS OTHERS ENDLOOP. V_SCRIPT. Agregamos la variable POS de tipo STRING. POS = 0. Para que esto funcione correctamente. POS = POS + 13. V_FORM = 'ZDUMMY_FORM'. DATA: V_FORM(14) TYPE C. Inicializamos la variable POS en 0. Ahora. luego de haber impreso el contenido del elemento. aumentamos el valor de la variable POS en 13. con lo cual el texto ID Programa quedaría más centrado en la caja.Para terminar. podríamos crear una tabulación. Nos vamos a Paragraph Formats . Seleccionamos nuestro párrafo por defecto y presionamos el botón Tabs (Tabuladores) . 184 . escribimos .Creamos una tabulación de 5 MM con alineación a la izquierda. Para agregar un tabulador. 185 . Grabamos. activamos y ejecutamos el programa. antes del texto.. Regresamos al Layout y cambiamos el formato del editor. . 186 .. puesto que no es una opción que esté muy a la vista. Y elegir Utilities Activate Debugger (Utilidades Activar Debugger).Debugger en SAPScript Hay que veces que necesitamos hacer un Debug a un SAPScript. ingresamos al transacción SE71 (Form Painter).No es de las mejores herramientas de SAP. veremos la siguiente ventana. y claro. aunque no mucha gente lo sepa. Esto es bastante sencillo. Ahora. al ejecutar el programa. Para activar el Debugger. para poder continuar con el Por lo general se utiliza el botón Single Step (Paso sencillo). 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). 187 .Simplemente presionamos OK Debugger. Con esto. . 188 .. son la nueva generación de formularios (Ok..No tan nuevas si consideramos a los Adobe Forms.SmartForms Introducción Los SmartForms. En realidad es cuestión de gustos. que no se incluyen en este libro) que reemplazan a los para algunos obsoletos formularios SAPScript.. Creando un estilo Para crear un estilo debemos ingresar a la transacción SMARTFORM y seleccionar el radio button Style (Estilo).Yo siempre he sido un fanático acerrimo del SAPScript. Debemos crear un nuevo nodo en la opción Paragraph Format (Formato de Párrafo).Lo nombramos ZTEST_ESTILO y presionamos el botón Create (Crear) . vamos a crear nuestro párrafo por defecto. 189 . tal como lo hicimos en el SAPScript. En esta ventana. tamaño e inclusive color (Claro. Tipo de Letra.para impresoras a colores. que seamos realistas. Y llenamos su descripción.Llamemos ST a este nuevo nodo.. es lo que menos abunda en las empresas).. 190 . Cuando hemos terminado. Y asignamos nuestro párrafo por defecto. 191 . hacemos doble clic en Header Data (Datos de Cabecera). activamos y salimos a la pantalla inicial. debemos asignar el estilo que creamos.Cuando terminamos. En la pestaña Output Options (Opciones de Salida). grabamos. Creando un Formulario Creamos nuestro primer SmartForm llamado ZPRIMER_SMARTFORM. 192 . así que podemos dejarla así. 193 . necesitamos una página y una ventana. Para poder escribir en esta ventana. Como vemos %PAGE1 está creada por defecto. Create Text (Crear Texto). Lo mismo ocurre con la ventana MAIN. debemos crear un texto de la siguiente manera.Al igual que en SAPScript. o asignarle un nuevo nombre. Clic derecho en MAIN. 194 . Llenamos el texto tal como hicimos con el SAPScript. veremos una pantalla como esta.Cuando creamos el texto. Para poder utilizar las variables dentro del SmartForms. debemos definir algunas variables globales. En la pestaña Tables (Tablas). asignamos una tabla interna. para esto nos vamos a Form Interface (Interface de Formulario). 195 . Ahora nos vamos a Global Definitions (Definiciones Globales) y luego a la pestaña Global Data (Datos Globales). Aquí creamos una estructura intermedia que recoge los datos del SmartForms y los almacena para poder mostrarlos en el formulario. Una vez creado. dentro del LOOP. debemos mover nuestro texto.Debemos crear un LOOP para poder asignar los valores de la tabla de parámetro a la tabla intermedia. 196 . En el LOOP debemos asignar los datos de la tabla hacia la tabla intermedia. REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. debemos crear el programa que va a llamar a nuestro SmartForms. * *=====================================================* * *=====================================================* 197 . Creando un programa de impresión Ahora. SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM INICIALIZAR.*=====================================================* * DECLARACION DE VARIABLES DATA: MODULO_FUNCION TYPE RS38L_FNAM. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 198 . PERFORM ABRIR_SMARTFORMS. NO_FUNCTION_MODULE = 2 = MODULO_FUNCION = 'ZPRIMER_SMARTFORM' CALL FUNCTION MODULO_FUNCION TABLES T_PROGRAMAS EXCEPTIONS = T_ZPROGRAMAS 199 . CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME IMPORTING FM_NAME EXCEPTIONS NO_FORM OTHERS = 1 = 3. "INICIALIZAR *&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SMARTFORMS. ENDFORM.*&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG. necesitamos una variable que tenga el mismo tipo que los Módulos de Funciones. NO_FUNCTION_MODULE = 2 = MODULO_FUNCION = 'ZPRIMER_SMARTFORM' 200 . Porque hacemos esto? Muy simple.FORMATTING_ERROR = 1 INTERNAL_ERROR SEND_ERROR USER_CANCELED OTHERS ENDFORM. Declaramos una variable llamada MODULO_FUNCION del tipo RS38L_FNAM. CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME IMPORTING FM_NAME EXCEPTIONS NO_FORM OTHERS = 1 = 3. por lo tanto. = 2 = 3 = 4 = 5. los SmartForms se generan como módulos de funciones. "ABRIR_SAPSCRIPT Revisemos el programa. DATA: MODULO_FUNCION TYPE RS38L_FNAM. Ejecutando el formulario Al igual que en el SAPScript. hacemos una llamada dinámica al SmartForms y pasamos los parámetros necesarios. Grabamos. activamos y ejecutamos el programa. se nos mostrará una pantalla de parámetros de impresión. CALL FUNCTION MODULO_FUNCION TABLES T_PROGRAMAS EXCEPTIONS FORMATTING_ERROR = 1 INTERNAL_ERROR SEND_ERROR USER_CANCELED OTHERS = 2 = 3 = 4 = 5.Utilizamos el módulo de funciones SSF_FUNCTION_MODULE_NAME para poder obtener el nombre del módulo de funciones que generó el SmartForms. 201 . = T_ZPROGRAMAS Con la variable MODULO_FUNCION. en este caso la tabla interna T_ZPROGRAMAS. 202 . es cuestión simplemente de ajustar las propiedades del texto. impresa en color azul.Tenemos nuestra lista. Si les parece que está un poco abajo. . Para esto. Eliminamos el LOOP que habíamos creado y creamos una nueva tabla.Utilizar una tabla para mostrar la información. 203 . debemos aprovechar una de las opciones más interesantes que nos brindan los SmartForms.Crear una tabla Si bien el formulario se ve bien.. vamos a modificar un poco nuestro programa. (Si imaginan hacer algo así como multiples box’s en SAPScript?). para poder asignar un nombre de línea.En la pestaña DATA (Datos) debemos hacer lo mismo que habíamos hecho en el LOOP. Lo cual nos servirá para definir los componentes de la tabla. asignar la tabla de parámetro a nuestra tabla intermedia. En la pestaña Table (Tabla). debemos hacer clic en el botón Details (Detalles) . 204 . Para crear la cabecera de nuestra tabla. 205 . nos posicionamos en Header y con un clic derecho escogemos Create (Crear) (Línea de Tabla). Table Line Escogemos el tipo de línea que hemos creado. una sola celda. 206 . así que vamos al nodo principal %TABLE1 a la pestaña Table y dentro del Formulario gráfico. pero nosotros necesitamos dos. solamente tenemos un %CELL1 es decir. dibujamos una línea vertical (Con esto creamos automáticamente un %CELL2).Como veremos. debemos agregar en cada uno un Texto para poder mostrar el título de cada campo. Como tenemos reservados los espacios para dos campos. 207 .Seguimos el mismo procedimiento para Main Area (Area Principal). creamos una Línea de Tabla. asignamos los textos y pasamos la variables &T_AUX_PROGRAMASID_PROG& y &T_AUX_PROGRAMAS-NOM_PROG& tal como hicimos con el SAPScript. Con esto. es decir. estamos listos para ejecutar el programa. hacemos clic sobre el botón Draw Lines and Columns (Dibujar líneas y columnas) deshabilitarlo. para Presionamos el botón Select Pattern (Seleccionar Patrón) . Seleccionamos los campos de nuestra línea de tabla (Utilizando la tecla Control). En el nodo principal de la tabla. 208 .Si queremos que se note que hemos utilizado una tabla. hacemos lo siguiente. . 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. lo veremos de la siguiente manera. 210 . creados con el Menu Painter. son los menús. 211 . Una adición importante y necesaria a los Dynpros. Estos son muy útiles cuando queremos crear programas con mayor capacidad de procesamiento gráfico. deberemos ingresar a la transacción SE51 (Screen Painter).Screen Painter y Menu Painter Introducción En ABAP. además de los reportes. podemos crear pantallas o dynpros. Screen Painter Para poder crear Dynpros o pantallas en ABAP. radio buttons o tablas. en los cuales podemos incluir diversos elementos tales como cajas de textos. establecemos el número de la pantalla. Es importante que el programa exista. . 212 . puesto que simplemente vamos a asociarle una pantalla. y en el campos Screen Number (Número de Pantalla). que explique para que va a ser utilizada la pantalla. no Aquí deberemos ingresar una descripción breve. llamar a pantallas distintas dependiendo de una condición dada. Como en el caso de los programas. ya que podemos tener muchas pantallas relacionadas entre si.En el campo Program (Programa) ingresaremos el nombre del programa en el cual se va a utilizar el dynpro. deberemos hacer clic en el botón Create (Crear) vamos a crear un programa nuevo. O inclusive. lo llenaremos solamente si es que luego de esta pantalla vamos a llamar a otra. En el caso de Next Screen (Siguiente pantalla). debemos hacer clic en el botón Layout (Disposición) . lo dejamos con el valor por defecto. 213 . Para poder comenzar a diseñar nuestra pantalla. En este caso. debemos especificar que tipo de Dynpro queremos crear. Los demás parámetros podemos dejarlos como están. por lo general utilizamos Normal.En Screen Type (Tipo pantalla). Botón de Selección o RadioButton. Permite crear este control mediante un ayudante paso a paso. Permite colocar un Dynpro de tipo SubScreen dentro de otro Dynpro de tipo Normal. Box. Wizard de Table Control o Grilla. sirve para crear labels o etiquetas descriptivas. Llamado también Tabla o Grilla. Permite crear este control mediante un ayudante paso a paso.Controles del Screen Painter Cursor que sirve para seleccionar y mover los controles dentro del dynpro. Pulsador o Botón. Área SubScreen. 214 . Campo de Entrada/Salida. Control de fichas o Control de Tabuladores. nos sirve tanto para recoger como para obtener datos. Table control. Campo de texto. Wizard de control de Fichas o Control de tabuladores. Casilla de Selección o Checkbox. Permite crear un contenedor para los controles. Permite establecer el status de una pantalla.Custom Control o Control Personalizado. bastará con seleccionarlos y arrástrarlos hacia el espacio de nuestro dynpro. 215 . es decir. Para poder crear cualquiera de estos controles. Nos permite crear elementos en tiempos de ejecución. Icono Status. si la ejecución de la pantalla fue exitosa o errónea. Muy utilizados para programación en ABAP Objects. Luego. 216 . obtenemos sus características y existe una relación directa con la Base de Datos). creamos un control Text Field (Campo de Texto). al cual llamaremos TEXT_FILTRO y que tendrá como texto “Filtro”. Vamos a crear una caja de texto.Ejemplo de Screen Painter Para este ejemplo. por lo cual. Una vez ingresado el nombre. Por lo tanto utilizaremos el nombre ZPROGRAMAS-ID. al cual vamos a asociarlo con un campo de la base de datos. mostraremos los campos seleccionados en base a ese filtro. vamos a hacer algo bastante sencillo. en donde especificaremos el valor que queremos utilizar como filtro y en una tabla o grilla. vamos a crear un control Input/Output Field (Campo de Entrada/Salida). se nos mostrará el siguiente mensaje (Esto es porque estamos utilizando el nombre de una tabla y un campo. Primero. 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 . Para poder acceder a las propiedades de este control. 218 . deberemos utilizar un control Text Field y otro control Input/Output Field.Ahora. Para poder crear los campos de nuestra tabla. 219 . Nuestra tabla. se llamará TABLA. para cada campo que deseemos mostrar. debemos crear nuestra tabla con el control Table Control . En este caso. 220 . *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. el primero T_ZPROGRAMAS-ID_PROG y el segundo T_ZPROGRAMAS-NOM_PROG. En este caso. es el programa control para el Dynpro. Para esto. debemos hacer clic en el botón Flow Logic (Flujo lógico) . Ambos referenciando a un campo de una tabla. que vamos a crear en nuestro programa. llamada T_ZPROGRAMAS. vamos a asociar los campos de nuestra tabla a una tabla interna. debemos crear la lógica de proceso para nuestra pantalla. * *=====================================================* Luego de haber creado nuestros controles en el Dynpro.Primero debemos crear el control Input/Output Field y luego el Text Field. Esta tabla vamos a definirla en el programa ZDUMMY_PRIMER_PROGRAMA que en este caso. debemos ingresar el siguiente código (Para esto. simplemente hacemos doble clic en el texto STATUS_0100). deberemos incluir el siguiente código marcado en rojo. Con esto. simplemente leemos el contenido de la tabla interna T_ZPROGRAMAS y lo asignamos a cada campo de nuestra tabla. 221 . 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. Para poder llenar la tabla con los datos obtenidos en base al filtro. 222 . o queremos crear un INCLUDE (Es decir. Por lo tanto. nos pregunta si queremos crearlo en el programa fuente. debemos crearlo aceptando el mensaje.En esta ventana. vamos a crearlo en el programa principal. nos avisan que el módulo STATUS_0100 no existe. Cuando el NetWeaver va a crear un nuevo módulo o función. En este caso. un programa adicional que será llamado por el programa principal). ID = ZPROGRAMAS-ID. 223 . SET TITLEBAR 'xxx'. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS.. Ahora.. TABLA-LINES = LINEAS. " STATUS_0100 OUTPUT ENDMODULE.Eso es porque vamos a verlos más adelante. ID TYPE ZPROGRAMAS-ID. * * SET PF-STATUS 'xxxxxxxx'. DATA: LINEAS TYPE I. Se darán cuenta de que los SET están comentados. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. podemos agregar el código necesario a nuestro programa.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. DATA: LINEAS TYPE I. * *=====================================================* * *=====================================================* * *=====================================================* 224 .REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. CALL SCREEN '100'. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS WITH HEADER LINE. IF ID NE SPACE. 225 . * * SET PF-STATUS 'xxxxxxxx'. " STATUS_0100 OUTPUT ENDMODULE. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. START-OF-SELECTION. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. CALL SCREEN '100'. SET TITLEBAR 'xxx'. En otras palabras. *&----------------------------------------------------* *& 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. TABLA-LINES = LINEAS. ENDIF. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. ENDMODULE. IF ID NE SPACE. DATA: LINEAS TYPE I. LINEAS de tipo I e ID ZPROGRAMAS-ID. que hemos creado una tabla en la pantalla 100. Finalmente. Creamos dos variables. ID = ZPROGRAMAS-ID. " STATUS_0100 OUTPUT ENDMODULE. TABLA-LINES = LINEAS. * * SET PF-STATUS 'xxxxxxxx'. ID TYPE ZPROGRAMAS-ID. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. llamamos a la pantalla 100. de tipo 226 . ENDIF. MODULE STATUS_0100 OUTPUT.debemos declarar por código. SET TITLEBAR 'xxx'. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. Finalmente asignamos la variable LINEAS (Que contiene la cantidad de líneas de la tabla interna) al campo LINES de nuestra tabla TABLA. Si la variable ID no está vacía (Es decir. le decimos cuantas líneas se deberían de mostrar en la tabla. Obtenemos la cantidad de líneas que hay en la tabla interna. debemos activar tanto el Dynpro como el programa. hemos ingresado un valor en la caja de texto). entonces podemos continuar. 227 . es decir. Seleccionamos todos los campos de la tabla ZPROGRAMAS siempre y cuando. el ID sea igual a nuestra variable ID.Al pasar el valor de ZPROGRAMAS-ID a la variable ID. significa que recogemos el valor de la caja de texto del dynpro y lo guardamos en una variable auxiliar. Para poder ejecutar el programa. utilizando el comando DESCRIBE TABLE. Si ingresamos el código de un lenguage. Por lo tanto debemos crear uno en la transacción SE41. veremos como funciona el programa. Si se fijan bien. se darán cuenta de que todos los botones en la barra de transacciones están deshabilitados. Esto se debe a que no hemos asociado un menú a nuestra pantalla. 228 . Menu Painter Lo primero que debemos hacer. debemos ingresar un texto breve o descripción que nos indique para que se utilizará este menú. es decir Online Status (Status en línea). que en este caso. En la ventana que nos muestra el NetWeaver. dejemos el que viene por defecto. Para ello. En cuanto al Status Type (Tipo de Status). 229 . es crear un Status. deberemos hacer clic en el botón Create (Crear) . va a ser el 100. como siempre. En la gran mayoría de los casos. se nos mostrará la siguiente pantalla.Una vez que aceptemos. Debemos hacer clic en este botón para poder expandirlo. solo nos va a importar esta sección. 230 . simplemente deberemos incluir la siguiente línea (O más bien. descomentarla). Con esto. nuestro menú está listo para utilizarse. para este ejemplo. Ahora. debemos grabar y activar.Nuevamente. solo nos interesa esta sección. Para poder agregarlo a nuestro programa. 231 . Aquí debemos establecer que botones queremos habilitar y cuales son sus nombre de función. SET PF-STATUS '100'. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. ENDMODULE.Pero no. cuando tengamos más botones.Aún debemos asignar las funciones que va a cumplir cada uno de los botones de nuestro menú. deberíamos incluir el OK_CODE dentro de nuestro Dynpro. y ‘100’ es el número de dicho menú. " USER_COMMAND_0100 INPUT En este caso. los tres botones hacen lo mismo. SET SCREEN 0. MODULE USER_COMMAND_0100 INPUT.. CLEAR SY-UCOMM. OK_CODE = SY-UCOMM. La variable del sistema SY-UCOMM. 232 . DATA: OK_CODE TYPE SY-UCOMM. debemos incluir el siguiente código. determina que valor tiene el botón que ha sido presionado.. CASE OK_CODE.. Aunque en este caso no es necesario.. Con esto parecería ser suficiente.El SET PF-STATUS le dice a nuestro Dynpro. así que no hay mucho problema. ENDCASE. para ello. LEAVE SCREEN. que queremos utilizar un menú creado por nosotros. así que vamos a la transacción SE51. 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, propiedades. podemos hacer doble clic para modificar sus 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, el ya estamos ID listos ya para un programar nuestro Muy MatchCode…Claro hacer...Si campo ustedes se preguntarán...¿Qué vamos a tiene MatchCode? 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) 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. y veremos una 243 DYNNUM = '100'. REFRESH RETURN_TAB. DYNPROFIELD = 'ZPROGRAMAS-ID'. SELECT ID INTO TABLE T_MATCHCODE_ID FROM ZPROGRAMAS. CLEAR RETURN_TAB. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD DYNPPROG = 'ID' = PROGNAME 244 .MODULE MATCH_CODE_ID INPUT. PROGNAME = SY-REPID. PROGNAME = SY-REPID. 245 . ENDMODULE. ENDIF. ZPROGRAMAS-ID = RETURN_TAB-FIELDVAL. Seleccionamos todos los ID’s de la tabla ZPROGRAMAS. DYNPROFIELD = 'ZPROGRAMAS-ID'. " MATCH_CODE_ID INPUT Revisemos un poco el código. DYNNUM = '100'.. SELECT ID INTO TABLE T_MATCHCODE_ID FROM ZPROGRAMAS.DYNPNR DYNPROFIELD VALUE_ORG TABLES VALUE_TAB RETURN_TAB EXCEPTIONS = DYNNUM = DYNPROFIELD = 'S' = T_MATCHCODE_ID = RETURN_TAB PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3.. IF RETURN_TAB-FIELDVAL NE SPACE. ENDIF. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD DYNPPROG DYNPNR DYNPROFIELD VALUE_ORG TABLES VALUE_TAB RETURN_TAB EXCEPTIONS PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3. 246 . REFRESH RETURN_TAB.El campo DYNPROFIELD almacena a que campo se va a aplicar el MatchCode. 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. ZPROGRAMAS-ID = RETURN_TAB-FIELDVAL. = T_MATCHCODE_ID = RETURN_TAB = 'ID' = PROGNAME = DYNNUM = DYNPROFIELD = 'S' IF RETURN_TAB-FIELDVAL NE SPACE. CLEAR RETURN_TAB. Esto es bastante sencillo. supongamos que queremos tener la posibilidad de elegir un registro y eliminarlo. y supone hacer unas cuantas modificaciones en los atributos de la tabla. (Además de agregar algunos registros más en nuestra tabla ZPROGRAMAS). Si hemos escogido algún valor. tenemos un MatchCode dinámico.. entonces lo mostramos en el campo ZPROGRAMAS-ID. 2. 247 . Listo. Nos muestra una ventana con los valores disponibles y el que hayamos elegido es guardado en la tabla RETURN_TAB.Eliminar registros en un table control Ahora.El módulo de funciones recibe las variables con la información del Dynpro y la tabla conteniendo los valores de los ID’s. que en este caso. La variable FILA nos a indicar cuando hayamos seleccionado un registro. Además.Debemos marcar el check w/SelColumn (con Selección de columna) y asignarle un nombre. 248 . vamos a agregar un botón llamado ELIMINAR. va a ser “FILA”. 249 . además de un Tooltip con el texto “Eliminar”.Como vemos. el botón tiene un FctCode llamado “ELIMINA” y un Icono llamado ICON_DELETE. MODULE ELIMINAR_FILA INPUT. el sistema va a recorrer todas las filas de nuestra tabla hasta encontrar la que esté seleccionada. IF FILA EQ 'X'. MODULE USER_COMMAND_0100. LOOP AT T_ZPROGRAMAS. en ese momento el 250 . y automáticamente. PROCESS AFTER INPUT. ENDLOOP. entonces continuamos. recordemos que esta variable va a ser equivalente a la del Dynpro. Si hemos presionado el botón ELIMINAR. ENDMODULE. ENDIF. IF SY-UCOMM EQ 'ELIMINA'. DATA: FILA TYPE C.Tenemos que ingresar al Flow Logic para crear un módulo asociado el botón ELIMINAR. Creamos el módulo dentro de nuestro programa. " ELIMINAR_FILA INPUT Declaramos una variable llamada FILA de tipo C. DELETE T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. ENDIF. MODULE ELIMINAR_FILA. . PROCESS AFTER INPUT. Claro. Ahora. por lo tanto. 3. necesitemos modificar algún registro de nuestro table control. simplemente necesitaríamos seleccionar la llave primaria de la tabla y hacer un DELETE TABLE. MODULE ELIMINAR_FILA.valor de FILA va a ser ‘X’.Escritura/Lectura en un table control Puede ser que en algún momento. se borra también de la tabla. Borramos este valor de nuestra tabla interna y como consecuencia. LOOP AT T_ZPROGRAMAS. Recuerden que quitamos este valor para otro de los ejemplos. esto no lo borra de la Base de Datos. deberíamos poder tener la posibilidad de Escritura y Lectura. 251 . MODULE USER_COMMAND_0100. aunque sería bastante sencillo hacer que lo haga. debemos crear un nuevo módulo en nuestro Screen Painter. Debemos modificar los atributos de la tabla para que sea de Escritura/Lectura. ENDMODULE.MODULE ACTUALIZA_TABLA. Ahora. ENDLOOP. Dentro del programa. 252 . La variable CURRENT_LINE nos indica que registro es el que estamos modificando. modificaremos el contenido del registro del table control que hemos modificado. MODIFY T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. " ACTUALIZA_TABLA INPUT Con esto. deberemos colocar el siguiente código al módulo. 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. MODULE ACTUALIZA_TABLA INPUT. En la primera casilla escribimos CHANGESTAT y presionamos ENTER.Para esto. vamos a agregar un pulsador en el menú (Menú Painter – SE41). Empecemos creando uno estático. podemos definir un Static Text (Texto Estático) o un Dynamic Text (Texto Dinámico). En este caso. 253 . el texto asociado a la función. 254 .En esta ventana. el icono asociado y finalmente el texto informativo. definimos el código de función asociado al pulsador. Cuando grabamos y activamos. En esta nueva ventana. deberemos hacer un clic al costado del Icono para una última ventana de propiedades. el sistema tomará el texto por defecto del pulsador.Debemos asignar una tecla de función a cada pulsador que creemos. 255 . En el caso de nos especificar ningún texto. vamos a elegir el F2. En este caso. Finalmente. debemos escoger el texto que acompañará al icono que hemos seleccionado. queda así. TEXTO_DINAMICO TYPE SMP_DYNTXT. Debemos seguir los pasos anteriores hasta que lleguemos a esta pantalla (Claro. DYNNUM TYPE SY-DYNNR. tendremos que crear una variable y asignarle valores para nuestro texto dinámico. En este caso.Le toca ahora al pulsador con texto dinámico. De vuelta en el programa. Asignaremos cualquier tecla de función y continuaremos. PROGNAME TYPE SY-REPID. Field name (Nombre Campo) es una variable que deberemos crear en nuestro programa. veamos como crearlo. 256 . Finalmente tendremos esto. DATA: DYNPROFIELD TYPE HELP_INFO-DYNPROFLD. debemos escoger Dynamic Text esta vez). Declaramos la tabla COLS como una línea de la tabla TABLACOLS. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. Nuevamente deben de estar como campos de salida. CALL SCREEN '100'. TEXTO_DINAMICO = 'Este es un texto dinámico'. START-OF-SELECTION. En el Screen Painter debemos cambiar los atributos de los componentes de la tabla. DATA: COLS LIKE LINE OF TABLA-COLS. En el programa. Esto es para que los componentes de la tabla estén protegidos por defecto.Y debemos también asignarle un texto inicial. deberemos hacer lo siguiente. 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'. START-OF-SELECTION. esto es porque TABLA-COLS es una Deep Structure 257 . CALL SCREEN '100'. solo necesitamos una cabecera y no toda la tabla. LOOP AT TABLA-COLS INTO COLS. ENDCASE. Agregamos el evento generado por el pulsador CHANGESTAT. Además. WHEN 'CHANGESTAT'. FORM CAMBIAR_ESTADO. MODULE USER_COMMAND_0100 INPUT. LEAVE SCREEN. COLS-SCREEN-INPUT = '1'. SET SCREEN 0. es decir. PERFORM PROCESAR_DATOS. PERFORM CAMBIAR_ESTADO. DATA: OK_CODE TYPE SY-UCOMM. " USER_COMMAND_0100 INPUT Para terminar. CASE OK_CODE. creamos el FORM CAMBIAR_ESTADO. WHEN 'PROCESAR'. ELSEIF COLS-SCREEN-INPUT = '1'.(Estructura profunda). IF COLS-SCREEN-INPUT = '0'. es una tabla dentro de otra tabla. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. ENDMODULE. 258 . TEXTO_DINAMICO = 'Modificar'. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. COLS-SCREEN-INPUT = '0'. 259 . ENDFORM. Verificamos el estado del campo INPUT. ENDIF. " CAMBIAR_ESTADO Hacemos un LOOP a la tabla TABLA-COLS y guardamos cada línea o registro dentro de nuestra tabla COLS. Cambiamos los estados. los textos del botón dinámico y finalmente modificamos la tabla para que los cambios queden registrados. entonces estamos visualizando y si es uno estamos modificando. si es cero. ENDLOOP. TEXTO_DINAMICO = 'Visualizar'. MODIFY TABLA-COLS FROM COLS. Trabajando con SubScreens 260 . los TABS no van a funcionar. Y por supuesto nuestro TabStrip Control llamado “TAB”. puesto que sin esto. Vamos a olvidarnos de nuestro programa anterior.Algunas veces necesitamos incluir pantallas completas de otras pantallas. Vamos a crear una nueva pantalla y un nuevo programa. sobre todo cuando tenemos que utilizar Tabs o Pestañas. Asignamos un nombre a cada TAB (Pestaña) del TabStrip Control. Es muy importante que definamos el Tipo de Función que este caso es P (Local Gui Function – Función GUI Local). y vamos a crear uno nuevo utilizando pestañas y un SubScreen. 261 . 262 . puesto que son contenedores que admiten únicamente pantalla de tipo SubScreen. Dentro de los SubScreens no podemos colocar ningún control.Creamos un SubScreen. La única propiedad que tenemos que definir para el SubScreen es el nombre. Así que debemos crear dos pantallas más. la 101 y 102. y lo asignamos al control TAB. pero esta vez de tipo SubScreen. CALL SUBSCREEN: SUBSCREEN_1 INCLUDING SY-REPID '0101'. PROCESS AFTER INPUT.Luego de haber creado las dos SubScreens. MODULE USER_COMMAND_0100. MODULE STATUS_0100. Con el INCLUDING referenciamos al programa control y al número de la pantalla. PROCESS BEFORE OUTPUT. 263 .SUBSCREEN_2. CALL SUBSCREEN: SUBSCREEN_2 INCLUDING SY-REPID '0102'. CALL SUBSCREEN: SUBSCREEN_1. Con el CALL SUBSCREEN llamamos a cada una de las pantallas SubScreen que creamos. este será el Flow Logic para la pantalla principal. Vamos a crear un Box o Caja con los siguientes atributos. en el PAI también utilizamos el CALL SUBSCREEN para llamar a las SubScreens. ZLENGUAJES_PROG-NOMBRE. 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. 264 . vamos a tener dos campos de Entrada/Salida. Además. los componentes tendremos que colocarlos dentro de cada SubScreen. por lo cual vamos a comenzar con el número 0101. tendremos que utilizar el nombre TABLACAMPO como nombre. vamos a crear un campo de texto para el código del programa. Si queremos que esté asociado con una tabla de la Base de Datos.Como podemos ver. Como mencioné lineas arriba. el nombre será ZPROGRAMAS-ID. Dentro del Box (Caja). En este caso. Finalmente. Cabe destacar que aunque tengamos pensado utilizar dos SubScreens.Lo mejor sería crear una estructura para cada una de ellas y problema resuelto. no podemos crear el campo ZPROGRAMASNOM_PROG en ambas pantallas. los nombres de los componentes no pueden repetirse. Este botón nos va a servir. puesto que una vez obtenidos los datos del programa. Pero aquí simplemente vamos a utilizar variables para el segundo SubScreen. es decir.. En el cual no podrán ser modificados. podremos modificarlos y mostrarlos en el segundo SubScreen. 265 . tendremos un botón llamado MODIFICAR con el código de función MODIFY.. indica que pestaña del TAB va a estar activa cuando ejecutemos el programa. "OBTENER_DATOS 266 . SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE. Para el botón PROCESAR vamos a crear el siguiente form. vamos a tener V_NOM_PROG y V_NOMBRE.Por lo tanto. ENDFORM. crear las variables correspondientes y crear el componente TAB_CONTROL. TAB_CONTROL-ACTIVETAB = 'TAB_1'. En el programa.ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID. deberemos declarar la tablas ZPROGRAMAS y ZLENGUAJES_PROG. La sentencia TAB_CONTROL-ACTIVETAB. CONTROLS TAB_CONTROL TYPE TABSTRIP. START-OF-SELECTION. CALL SCREEN '100'. FORM OBTENER_DATOS. CLEAR SY-UCOMM. No debemos olvidarnos del USER-COMMAND. MODULE USER_COMMAND_0100 INPUT. OK_CODE = SY-UCOMM. PERFORM OBTENER_DATOS. ENDCASE.Hacemos un INNER JOIN entre las dos tablas. WHEN 'PROCESS'. CASE OK_CODE. ENDMODULE. y obtenemos los valores NOMBRE y NOM_PROG. DATA: OK_CODE TYPE SY-UCOMM. los cuales son guardados en los Campos de Entrada/Salida del Dynpro. " USER_COMMAND_0100 INPUT 267 . Cuando ingresamos el primer código. los datos se quedan pegados. STEPL TYPE DYNPREAD-STEPL. existe una función que actualiza los Dynpros. todo va bien. nos vamos a dar cuenta de algo bastante peculiar. y como debe ser. * *=====================================================* 268 . debemos crear los siguientes TYPES y Tablas Internas. FIELDNAME TYPE DYNPREAD-FIELDNAME. Esto es porque estamos trabajando en un SubScreen y los datos no se actualizan directamente. FIELDVALUE TYPE DYNPREAD-FIELDVALUE. Para esto. Por suerte... pero con el segundo. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TAB.Cuando ejecutamos el programa. CALL FUNCTION 'DYNP_UPDATE_FIELDS' EXPORTING DYNAME DYNUMB REQUEST TABLES = SY-CPROG = <FS_MY_DYNP>-DYNUMB = 'A' 269 .FIELDINP TYPE DYNPREAD-FIELDINP. <FS_MY_TAB> LIKE LINE OF MY_TAB. TYPES: BEGIN OF DYNP. LOOP AT MY_DYNP ASSIGNING <FS_MY_DYNP>. END OF DYNP. END OF TAB. * *=====================================================* Nuestro FORM para actualizar el Dynpro será el siguiente (Aunque primero debemos crear dos Field-Symbols. FIELD-SYMBOLS: <FS_MY_DYNP> LIKE LINE OF MY_DYNP. DYNUMB TYPE D020S-DNUM. FORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: MY_TAB TYPE STANDARD TABLE OF TAB. MY_DYNP TYPE STANDARD TABLE OF DYNP. REFRESH: MY_TAB. SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-NOM_PROG. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-ID. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-ID'. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-NOM_PROG'. ENDFORM. APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>. APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>. podemos mejorar la rutina 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. Gracias a esto.DYNPFIELDS = MY_TAB.ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID. FORM OBTENER_DATOS. ENDLOOP. IF SY-SUBRC EQ 0. MY_DYNP. APPEND INITIAL LINE TO MY_TAB 270 . WHEN 'PROCESS'. <FS_MY_DYNP>-DYNUMB = '0101'. "OBTENER_DATOS Primero.ASSIGNING <FS_MY_TAB>. MODULE USER_COMMAND_0100 INPUT. 271 . <FS_MY_TAB>-FIELDVALUE = ZLENGUAJES_PROG-NOMBRE. PERFORM OBTENER_DATOS. agregamos los campos del Dynpro a nuestra tabla MY_TAB. Finalmente llamamos al FORM ACTUALIZAR_DYNPRO pasando las tablas como parámetros. <FS_MY_TAB>-FIELDNAME = 'ZLENGUAJES_PROG-NOMBRE'. DATA: OK_CODE TYPE SY-UCOMM. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. APPEND INITIAL LINE TO MY_DYNP ASSIGNING <FS_MY_DYNP>. podemos continuar con el botón MODIFICAR. Con esto listo. ENDFORM. además agregamos el número del Dynpro a nuestra tabla MY_DYNP. CASE OK_CODE. ENDIF. si el SELECT es exitoso. PERFORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP. ENDCASE. " TRASPASAR_VALORES 272 . FORM TRASPASAR_VALORES.WHEN 'MODIFY'.V_NOMBRE. V_NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. (Aunque antes creamos un par de variables que están relacionadas con los campos del segundo SubScreen). DATA: V_NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. CLEAR: V_NOM_PROG. MOVE ZLENGUAJES_PROG-NOMBRE TO V_NOMBRE. PERFORM TRASPASAR_VALORES. MOVE ZPROGRAMAS-NOM_PROG TO V_NOM_PROG. ENDMODULE. ENDFORM. " USER_COMMAND_0100 INPUT Creamos el nuevo FORM. 273 . En el Flow Logic. que es el de Listbox (Lista desplegable). pero esta vez. utilizando un lista desplegable que nos muestre todos los códigos de programas. es obtener los datos de la tabla ZPROGRAMAS. crearemos un módulo que llene la lista con datos.Utilizando Listas Deplegables Lo que vamos a hacer ahora. Debemos crear un campo de Entrada/Salido asociado al campo ZPROGRAMAS-ID. 274 . pero debemos asignarle un atributo especial. debemos crear algunas variables. un Type e inclusive un Type-Pool. PROCESS AFTER INPUT. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: VALUES TYPE VRM_VALUES. Como era de esperarse. * *=====================================================* * *=====================================================* * *=====================================================* Como ven. MODULE USER_COMMAND_0100. MODULE STATUS_0100.. nuevamente necesitamos una tabla con cabecera. FC_VALUES LIKE VALUES WITH HEADER LINE. MODULE LLENAR_LISTA_DESPLEGABLE..Esto es porque el componente Listbox sigue siendo parte del ABAP antiguo. tablas internas. 275 .PROCESS BEFORE OUTPUT. *=====================================================* * DECLARACION DE VARIABLES DATA: ID TYPE VRM_ID. *=====================================================* * DECLARACION DE TYPES TYPE-POOLS: VRM. IF ID EQ SPACE. SELECT ID NOMBRE INTO (FC_VALUES-KEY. ENDMODULE. CALL FUNCTION 'VRM_SET_VALUES' EXPORTING ID VALUES EXCEPTIONS ID_ILLEGAL_NAME OTHERS ENDIF. ya se que se ve un poco redundante. ENDLOOP. MODULE LLENAR_LISTA_DESPLEGABLE OUTPUT. ID = 'ZPROGRAMAS-ID'. APPEND FC_VALUES.Este es el código que utilizaremos para llenar con datos la lista. " LLENAR_LISTA_DESPLEGABLE OUTPUT = 1 = 2. APPEND FC_VALUES TO VALUES. = ID = VALUES 276 . ENDSELECT. LOOP AT FC_VALUES. pero la estructura de la función que genera la lista así lo requiere.FC_VALUES-TEXT) FROM ZLENGUAJES_PROG. que es el que finalmente crea la lista despegable. veremos que la lista está llena. simplemente agregamos un código de función al componente. 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. puesto que si seleccionamos un lenguaje de programación. además. antes de poder continuar. Así que vamos a hacer que cuando seleccionemos el lenguaje. nos muestra el nombre del lenguaje en un espacio muy reducido.Aunque no es nada recomendable utilizarlo. Para esto. se muestren los datos. no nos muestra los datos. así que deberíamos ampliar un poco su tamaño. pero no hace nada. sin necesidad de un botón auxiliar. 277 . en este caso necesitamos el SELECT-ENDSELECT (El GOTO del ABAP). Si ejecutamos el programa. IF SY-SUBRC NE 0. ENDIF.ZPROGRAMAS-NOM_PROG) FROM ZPROGRAMAS WHERE ID EQ ZPROGRAMAS-ID. podemos llamar al FORM OBTENER_DATOS.Dentro del programa. ENDFORM. WHEN 'LISTA'. SELECT SINGLE ID_PROG NOM_PROG INTO (ZPROGRAMAS-ID_PROG. CASE OK_CODE. " OBTENER_DATOS 278 . CLEAR: ZPROGRAMAS-ID_PROG. " USER_COMMAND_0100 INPUT Con esto listo.ZPROGRAMAS-NOM_PROG. FORM OBTENER_DATOS. OK_CODE = SY-UCOMM. DATA: OK_CODE TYPE SY-UCOMM. ENDCASE. agregamos una llamada al código de función. PERFORM OBTENER_DATOS. ENDMODULE. MODULE USER_COMMAND_0100 INPUT. CLEAR SY-UCOMM. cuando elegimos un valor de la lista desplegable. 279 .Ahora. podemos obtener los datos asociados. DATA: DYNPRO_VALUES TYPE TABLE OF DYNPREAD WITH HEADER LINE. FREE FIELD_VALUE. pero nos damos cuenta de que este no está activo hasta que presionamos la tecla ENTER o activamos algún evento. FIELD_VALUE-FIELDNAME = 'ZPROGRAMAS-ID'. PROCESS AFTER INPUT. por eso. Necesitaremos crear dos tablas internas y una variable. FIELD_VALUE LIKE LINE OF DYNPRO_VALUES. existe una función muy útil para leer los valores de un Dynpro. 280 . necesitamos leer el valor de un componente del Dynpro. MODULE READ_DYNP_VALUES INPUT. DATA: DYNUM TYPE D020S-DNUM. FREE DYNPRO_VALUES. MODULE READ_DYNP_VALUES.Leyendo datos de un Dynpro Algunas veces. APPEND FIELD_VALUE TO DYNPRO_VALUES. Y creamos un módulo para leer los valores del Dynpro. Obviamente no podemos obligar al usuario a presionar ENTER o activar un evento. MODULE USER_COMMAND_0100. ZPROGRAMAS-ID = DYNPRO_VALUES-FIELDVALUE. READ TABLE DYNPRO_VALUES WITH KEY FIELDNAME = 'ZPROGRAMAS-ID'. Si la función puede leerlo. ENDMODULE. y el valor que queremos leer. entonces lo asignamos a nuestro campo o a donde lo necesitemos. ENDIF. 281 . " READ_DYNP_VALUES INPUT = SY-CPROG = DYNUMB Como podemos ver. tenemos que pasar el número del Dynpro.DYNUMB = '0100'. CALL FUNCTION 'DYNP_VALUES_READ' EXPORTING DYNAME DYNUMB TABLES DYNPFIELDS = DYNPRO_VALUES. IF SY-SUBRC EQ 0. es un programa capaz de recibir parámetros de entrada y producir un resultado. Para empezar. que sirven para la comunicación entre sistemas externos y el NetWeaver. días. meses. utilizaremos el grupo de funciones que creamos en la sección Creando una vista de Actualización. Los módulos de función son creados en la transacción SE37. fuera del programa que lo utiliza. en que puede poseer una estructura bastante compleja y debe ser diseñado en su propio entorno.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. En la transacción SE37. los Standard y los RFC (Remote Function Call – Llamada de Procedimiento Remoto). Se diferencia de una función normal. Para 282 . Creando nuestra primera función Como siempre. la mejor explicación es un ejemplo. Por ejemplo. definamos que va a hacer nuestra función. calcular la edad de una persona en años. así que vamos a crear uno bastante sencillo. Para esto. crearemos nuestra ZDUMMY_FUNCTION. En este caso. Cuando creemos la función. 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. hay ciertos campos que debemos ir llenando. llamado FECHA_NAC de tipo SY-DATUM. solo vamos a utilizar un parámetro de entrada. 283 . Por lo tanto.esto. Vamos a llamarla ZEDAD_STR. meses y días. necesitaremos crear una estructura que contenga dichos campos. activamos y salimos. En la pestaña Changing (Cambiando). grabamos. 284 . Este botón. Basta con hacer clic en el botón Create (Crear) para ingresar al editor. nos permite crear un texto de ayuda que indica que hace o que necesita el parámetro para funcionar correctamente. hay dos CheckBox. mantenemos los valores por defecto. Escribimos un pequeño texto descriptivo. es decir. En este caso. Para todos los parámetros existen un botón muy importante llamado Long text (Texto largo) . que hará referencia a la estructura que hemos creado. dejamos ambos como están.Como podemos ver. Optional (Opcional). 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. vamos a crear nuestro parámetro de salida. Antes de comenzar con el código. por ejemplo. no va a ser el cálculo más exacto. es importante saber que podemos asignar excepciones. Finalmente. FUNCTION ZDUMMY_FUNCTION. Esto lo hacemos ingresando a la pestaña Exceptions (Excepciones).. que son errores que puede encontrar la función. *"----------------------------------------------------*"*"Local Interface: *" *" *" IMPORTING REFERENCE(FECHA_NAC) TYPE CHANGING SY-DATUM 285 .Luego de esto. pero a modo de ejemplo nos va a ser útil.funcione. 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.. indicándonos que el texto ha sido asignado correctamente. Claro. si la fecha de nacimiento ingresada como parámetro es mayor que la fecha actual. deberíamos mostrar un mensaje de error. podemos darnos cuenta de que el botón ha cambiado. RAISE EDAD_FUERA_RANGO. ZDAYS = 30 . ZMONTHS = FECHA_NAC+4(2). IF SY-DATUM+6(2) LT ZDAYS.1. TABLA_EDAD-ZYEARS = ZYEARS. 286 . ZDAYS = ZDAYS + SY-DATUM+6(2). ENDIF. ZMONTHS = ZMONTHS . ZDAYS(2) TYPE C.*" *" *" REFERENCE(TABLA_EDAD) TYPE EXCEPTIONS EDAD_FUERA_RANGO ZEDAD_STR *"----------------------------------------------------DATA: ZYEARS(4) TYPE C. IF FECHA_NAC GT SY-DATUM. ENDIF. ZYEARS = FECHA_NAC+0(4). TABLA_EDAD-ZMONTHS = ZMONTHS. IF SY-DATUM+4(2) LT ZMONTHS. ENDIF. ZDAYS = FECHA_NAC+6(2).ZYEARS.1. TABLA_EDAD-ZDAYS = ZDAYS. ZYEARS = SY-DATUM+0(4) . ZYEARS = ZYEARS . ZMONTHS = SY-DATUM+4(2) + 1.ZDAYS. ZMONTHS(2) TYPE C. ZDAYS = FECHA_NAC+6(2). RAISE EDAD_FUERA_RANGO. Si la fecha de nacimiento ingresada. las fechas se almacenan en un orden inverso. por lo tanto. al ingresar nosotros 22. una para guardar el año. ZMONTHS = FECHA_NAC+4(2). ZMONTHS(2) TYPE C. ZYEARS = FECHA_NAC+0(4).1977 se almacena como 19771122. ENDIF. Entonces. Además una variable auxiliar para los meses. Declaramos 3 variables. meses y días en variables. al 287 . ZMONTHS_AUX TYPE C. DATA: ZYEARS(4) TYPE C.ENDFUNCTION. En SAP. ZDAYS(2) TYPE C. es menor a la fecha actual del sistema. IF FECHA_NAC GT SY-DATUM. lanzamos un mensaje de error. Revisemos un poco el código.ZYEARS. para poder obtener los años. es decir. ZYEARS = SY-DATUM+0(4) . utilizamos posiciones de inicio y cantidad de caracteres.11. otra el mes y la última los días. Restamos el año actual. Restamos la cantidad de meses a 12. 288 . ENDIF. IF SY-DATUM+6(2) LT ZDAYS. entonces a 30 le restamos la cantidad de días. IF SY-DATUM+4(2) LT ZMONTHS. ZDAYS = 30 . ZMONTHS_AUX = 12 . Para probar nuestra función. ZDAYS = ZDAYS + SY-DATUM+6(2). 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. “Toma 4 caracteres.ZMONTHS. comenzando desde el carácter 0”.tener nostros FECHA_NAC+0(4) estamos diciendo. ZMONTHS = ZMONTHS . menos el año del parámetro.ZDAYS. finalmente. ZMONTHS = SY-DATUM+4(2) + ZMONTHS.1. entonces debemos restar un año. ENDIF. Si el mes actual es menor que el mes del parámetro.1. ZYEARS = ZYEARS . En otras palabras 1977. simplemente debemos ejecutarla presionando la tecla F8 o el botón Test/Exectute (Probar/Ejecutar) . sumamos esos meses de diferencia. para saber cuantos hay de diferencia. 289 .Ingresamos una fecha de nacimiento y lo ejecutamos. Además podríamos hacer un debug si presionaramos el botón Debugging o las teclas Ctrl + F7 . ya sea con el botón Execute (Ejecutar) o presionando F8 . debemos hacer clic en Details View/Edit (Visualizar/Editar Detalles) . Para ver más claramente el resultado. 290 . la manera más sencilla de llamar a una función es con el botón Pattern (Patrón) en una sección anterior. es hora de llamarla desde un programa. Si queremos ver el resultado con un mayor detalle. Ahora que ya vimos que nuestra función hace lo que tiene que hacer. 01 mes y 09 días. tal y como vimos REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. Llamando funciones desde un programa Dentro de nuestro programa. deberemos presionar el botón Single Entry (Entrada Individual) o presionar los botones Shift + F7 .30 Años. WRITE: 'La edad ingresada está fuera del rango'. *=====================================================* * Selection screen SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME. = 2. 'Años'. = TABLA_EDAD = P_FECHA * *=====================================================* * *=====================================================* * *=====================================================* 291 . WRITE: 'Su edad actual es'. TABLA_EDAD-ZYEARS.*=====================================================* * DECLARACION DE TABLAS DATA: TABLA_EDAD TYPE ZEDAD_STR. PARAMETERS: P_FECHA TYPE SY-DATUM. CALL FUNCTION 'ZDUMMY_FUNCTION' EXPORTING FECHA_NAC CHANGING TABLA_EDAD EXCEPTIONS EDAD_FUERA_RANGO = 1 OTHERS IF SY-SUBRC <> 0. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. ELSE. SELECTION-SCREEN END OF BLOCK DATA. 'Meses'. Introducción BAPIS Una BAPI (Business Application Programming Interface – Interface de Programación de Aplicaciones de Negocio). 'Días'. realizar contabilizaciones. ENDIF. como por ejemplo. El código es bastante sencillo y no necesita mayor explicación. 292 . Aunque las BAPI’s son utilizadas para realizar tareas específicas. TABLA_EDAD-ZDAYS. obtenemos los datos y los mostramos en pantalla. cargar datos maestros.TABLA_EDAD-ZMONTHS. crear pedidos. Llamamos a la función. etc. no es en el fondo más que un módulo de funciones con características de RFC. las BAPI’s cuentan con su propia transacción llamada justamente BAPI. Por eso. puesto que cuentan con muchos mecanismos de control y aseguramiento. Además. 293 . encapsulan operaciones complejas en una simple interfaz.Las BAPI’s son estables. necesitamos una función muy importante llamada REUSE_ALV_GRID_DISPLAY. así que veamos como sería el esqueleto del programa. es el uso de un TYPE-POOLS. promedios y muchas cosas más. Otro punto importante. ABAP. mostrar subtotales. ordenar datos. puesto que una vez que tengamos lista la tabla interna. Lo primero que hay que hacer. llamado SLIS. 294 .ALV (ABAP List Viewer) Introducción En ABAP es muy común crear reportes que muestren información de varias tablas. Estas listas son interactivas. es obtener los datos tal como lo haríamos en un programa normal. será muy sencillo generar el ALV. 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. Estos reportes. nos ofrece los ALV’s que son Visores de Listas ABAP. Creando un ALV Para crear un ALV. por lo general son bastante sencillos y estáticos puesto que simplemente muestran información. Este TYPE-POOLS. y nos permiten ocultar o visualizar columnas. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. *=====================================================* * Selection screen SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. ID_PROG TYPE ZPROGRAMAS-ID_PROG. END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TYPE-POOLS TYPE-POOLS: SLIS.*=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. SELECT-OPTIONS: * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* 295 . CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. " OBTENER_DATOS * *=====================================================* Vamos a necesitar crear algunas tablas internas para poder llenar las estructuras del ALV. así como algunas variables para manejar su formato de visualización.S_IDPROG FOR ZPROGRAMAS-ID_PROG. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. ENDFORM. * *=====================================================* 296 . SELECTION-SCREEN END OF BLOCK DATA. PERFORM OBTENER_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 * *&----------------------------------------------------* FORM OBTENER_DATOS. GS_SORT TYPE SLIS_T_SORTINFO_ALV. G_TITULO TYPE SY-TITLE. que se dispara cuando se ha terminado la selección de datos.I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. *=====================================================* * END-OF-SELECTION END-OF-SELECTION. *=====================================================* * END-OF-SELECTION END-OF-SELECTION. G_REPID TYPE SY-REPID. PERFORM INIT_LAYOUT. *=====================================================* * DECLARACION DE VARIABLES DATA: G_PROGRAM TYPE SY-REPID. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. PERFORM BUILD_SORT. PERFORM F_GENERAR_LISTA_ALV. * *=====================================================* En este evento. vamos a agregar una serie de funciones que se van a encargar de formar el ALV. * *=====================================================* 297 . * *=====================================================* Vamos a agregar un nuevo evento. ordenación va a ser ascendente. FORM INIT_LAYOUT.Vamos a crear y analizar cada una de estas funciones. ENDFORM. indicamos el número de la columna por la cual vamos a ordenar la lista. el segundo gris. el tercero blanco. " BUILD_SORT Primero. el primero blanco. <FS_SORT>-SPOS = 1. segundo. APPEND INITIAL LINE TO GS_SORT ASSIGNING <FS_SORT>. " INIT_LAYOUT Indicamos que queremos que el reporte se muestre con colores intercalados por registro. etc. ENDFORM. finalmente indicamos que la FORM FORMATEAR_DATOS_ALV_DET USING T_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. es decir. indicamos el nombre del campo relacionado a dicha columna. <FS_SORT>-UP = 'X'. <FS_SORT>-FIELDNAME = 'ID_PROG'. FORM BUILD_SORT. 298 . GS_LAYOUT-ZEBRA = 'X'. L_FIELDCAT-COL_POS = 1. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-SELTEXT_L = 'Entorno'. L_FIELDCAT-FIELDNAME = 'NOMBRE'. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. CLEAR L_FIELDCAT. L_FIELDCAT-COL_POS = 3. APPEND L_FIELDCAT TO T_FIELDCAT. L_FIELDCAT-FIELDNAME = 'NOM_PROG'. L_FIELDCAT-OUTPUTLEN = 15. L_FIELDCAT-SELTEXT_L = 'Id'.DATA: L_FIELDCAT TYPE SLIS_FIELDCAT_ALV. L_FIELDCAT-FIELDNAME = 'ID_PROG'. L_FIELDCAT-OUTPUTLEN = 5. L_FIELDCAT-SELTEXT_L = 'Nombre Programa'. CLEAR L_FIELDCAT. APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-OUTPUTLEN = 15. 299 . L_FIELDCAT-OUTPUTLEN = 10. L_FIELDCAT-SELTEXT_L = 'Nombre Lenguaje'. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-COL_POS = 2. L_FIELDCAT-COL_POS = 4. L_FIELDCAT-FIELDNAME = 'ENTORNO'. CLEAR L_FIELDCAT. APPEND L_FIELDCAT TO T_FIELDCAT. puesto que indica que campos deben leerse. SELTEXT_L es el texto que se va a mostrar en el campo. que luego es usada para llenar la tabla I_FIELDCAT que se pasa finalmente al ALV. el ALV soporta hasta 65 campos sin ningún problema. L_FIELDCAT-SELTEXT_L = 'Conexión con SAP'.APPEND L_FIELDCAT TO T_FIELDCAT. ENDFORM. L_FIELDCAT-FIELDNAME = 'CONEX_SAP'. COL_POS es la posición que va a tener el campo dentro del ALV. "FORMATEAR_DATOS_ALV_DET La tabla L_FIELDCAT se llena con todos los campos que queremos mostrar en nuestro ALV. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. OUTPUTLEN es la cantidad de caracteres de salida. Con todos los ingredientes listos. de que tamaño deben de ser mostrados. L_FIELDCAT-COL_POS = 5. en que posición. APPEND L_FIELDCAT TO T_FIELDCAT. solo nos falta llamar al ALV. L_FIELDCAT-OUTPUTLEN = 15. TABNAME es el nombre de la tabla que contiene la estructura del ALV. y que texto va a describirlos en la cabecera. En este ejemplo hemos utilizado pocos campos. Este FORM es el más importante. esta es apendada a la tabla T_FIELDCAT. CLEAR L_FIELDCAT. FIELDNAME es el nombre del campo que queremos mostrar. y hasta donde mi experiencia personal ha llegado. 300 . G_PROGRAM = SY-REPID.FORM F_GENERAR_LISTA_ALV. (Esta variable se asigna al parámetro I_GRID_TITLE). CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE I_GRID_TITLE IS_LAYOUT IT_FIELDCAT IT_SORT TABLES T_OUTTAB EXCEPTIONS PROGRAM_ERROR OTHERS IF SY-SUBRC <> 0. (Esta variable se asigna al parámetro I_CALLBACK_PROGRAM. " F_GENERAR_LISTA_ALV = 1 = 2. G_TITULO = 'Lista de Programas'. ENDIF. = T_PROGRAMAS = ' ' = G_TITULO = GS_LAYOUT = I_FIELDCAT = GS_SORT[] I_CALLBACK_PROGRAM = G_PROGRAM G_PROGRAM es el programa al cual está enlazado el ALV. G_TITULO es el título que va a llevar el listado ALV. 301 . EXIT. ENDFORM. I_FIELDCAT almacena los campos que conforman el ALV. (Esta tabla se asigna al parámetro T_OUTTAB). GS_SORT almacena el orden del ALV. T_PROGRAMAS es la tabla que almacena todos los registros obtenidos en el INNER JOIN.GS_LAYOUT almacena el formato del listado. Ahora. podemos ejecutar el programa. (Esta tabla se asigna al parámetro IT_FIELDCAT). 302 . (Esta tabla se asigna al parámetro IS_LAYOUT). (Esta tabla se asigna al parámetro IT_SORT). ENDFORM.Ahora que ya vimos como es un ALV. FORM INIT_LAYOUT. 303 . así que cambiamos el comando. Supongamos que no queremos que sea de tipo ZEBRA. Agregando una Cabecera al Reporte Supongamos que queremos agregar una cabecera que muestre información en el ALV. GS_LAYOUT-ZEBRA = ' '. sino a varias que muestren mayor información. investigemos un poco. " INIT_LAYOUT Como podrán ver. y con esto no me refiero a una línea como en el caso anterior. se nota bastante la diferencia. Tenemos que agregar dos tabla nuevas que almacenen los título que vamos a mostrar en la cabecera. * *=====================================================* GS_LIST_TOP_OF_PAGE almacena los título de la cabecera. I_EVENTS TYPE SLIS_T_EVENT.*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. 304 . FORM F_FORMATO_PAGE CHANGING GT_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. PERFORM BUILD_SORT. PERFORM F_GENERAR_LISTA_ALV. GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. *=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. Además necesitamos dos nuevas funciones. I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. * *=====================================================* F_FORMATO_PAGE nos permite definir el texto de la cabecera. PERFORM F_FORMATEAR_EVENTOS_ALV USING I_EVENTS[]. PERFORM INIT_LAYOUT. PERFORM F_FORMATO_PAGE CHANGING GT_LIST_TOP_OF_PAGE. mientras que I_EVENT controla los eventos del ALV. GS_LINE-TYP = 'H'. GS_LINE-INFO es el texto que se va a mostrar. 305 . CLEAR GS_LINE. ENDFORM. CLEAR GS_LINE.DATA: GS_LINE TYPE SLIS_LISTHEADER. APPEND GS_LINE TO GT_TOP_OF_PAGE. CONCATENATE 'HORA:' SY-UZEIT INTO GS_LINE-INFO SEPARATED BY SPACE. FORM F_FORMATEAR_EVENTOS_ALV USING P_EVENTS TYPE SLIS_T_EVENT. DATA: L_EVENTS TYPE SLIS_ALV_EVENT. Mientras que el segundo. nos permite definir el evento que requiere el ALV para poder activar la cabecera. H equivale a Header (Cabecera). "F_FORMATO_PAGE GS_LINE-TYP es el tipo de cabecera. GS_LINE-TYP = 'H'. APPEND GS_LINE TO GT_TOP_OF_PAGE. CONCATENATE 'FECHA:' SY-DATUM INTO GS_LINE-INFO SEPARATED BY SPACE. GS_LINE se adiciona a la tabla GT_TOP_OF_PAGE. ENDFORM. En este caso. Y como utilizamos una función que crea el ALV. "F_FORMATEAR_EVENTOS_ALV Declaramos una variable llamada L_EVENTS que controla los eventos. ENDFORM. L_EVENTS-NAME = 'TOP_OF_PAGE'. L_EVENTS-FORM = 'TOP_OF_PAGE'. 306 .CLEAR L_EVENTS. queremos que el evento sea TOP_OF_PAGE es decir. FORM F_GENERAR_LISTA_ALV. G_PROGRAM = G_TITULO = SY-REPID. "TOP_OF_PAGE La función REUSE_ALV_COMMENTARY_WRITE es la coloca el título en el ALV. debemos indicarle que evento tiene que ser activado. APPEND L_EVENTS TO P_EVENTS. un último FORM que asigna la cabecera al ALV. FORM TOP_OF_PAGE. Para terminar. la cabecera del ALV. CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE' EXPORTING IT_LIST_COMMENTARY = GT_LIST_TOP_OF_PAGE. G_TITULO = 'Lista de Programas'. podremos ver esto. ENDIF. 307 . = T_PROGRAMAS = ' ' = G_TITULO = GS_LAYOUT = I_FIELDCAT = GS_SORT[] = I_EVENTS I_CALLBACK_PROGRAM = G_PROGRAM Debemos agregar el parámetro IT_EVENTS que recibe la tabla I_EVENTS. que contiene los detalles del evento. ENDFORM. " F_GENERAR_LISTA_ALV = 1 = 2. cuando lo ejecutamos. CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE I_GRID_TITLE IS_LAYOUT IT_FIELDCAT IT_SORT IT_EVENTS TABLES T_OUTTAB EXCEPTIONS PROGRAM_ERROR OTHERS IF SY-SUBRC <> 0. Ahora. EXIT. Claro que la fecha y lo hora se ven bastante mal. FORM F_FORMATO_PAGE CHANGING GT_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. HORA(10) TYPE C. CONCATENATE SY-UZEIT+0(2) SY-UZEIT+2(2) SY-UZEIT+4(2) 308 . obtener los componentes de la fecha y la hora. Podemos corregirlos de una manera muy sencilla. Simplemente debemos de crear dos variables de tipo texto. CONCATENATE SY-DATUM+6(2) SY-DATUM+4(2) SY-DATUM+0(4) INTO FECHA SEPARATED BY '/'.”. para luego asignarlos a nuestra tabla de cabecera. DATA: GS_LINE TYPE SLIS_LISTHEADER. y concatenarlos utilizando separadores tales como “/” y “. esto es porque se muestran en el formato interno de SAP. FECHA(10) TYPE C. GS_LINE-TYP = 'H'. "F_FORMATO_PAGE El nuevo ALV se vería así. APPEND GS_LINE TO GT_TOP_OF_PAGE.INTO HORA SEPARATED BY ':'. GS_LINE-TYP = 'H'. CLEAR GS_LINE. CONCATENATE 'FECHA:' FECHA INTO GS_LINE-INFO SEPARATED BY SPACE. CLEAR GS_LINE. 309 . APPEND GS_LINE TO GT_TOP_OF_PAGE. CONCATENATE 'HORA:' HORA INTO GS_LINE-INFO SEPARATED BY SPACE. ENDFORM. G_REPID TYPE SY-REPID. debemos asignar un código de función. GS_SORT TYPE SLIS_T_SORTINFO_ALV. que es el nombre del evento que va a manejar. G_USER_COMMAND TYPE SLIS_FORMNAME VALUE 'USER_COMMAND'. vamos a definir el evento “clic” y después un par de ejemplos de su aplicación. debemos agregar una nueva variable para manejar este evento. 310 . Primero que nada. hacer clic en una fila. *=====================================================* * DECLARACION DE VARIABLES DATA: G_PROGRAM TYPE SY-REPID. G_TITULO TYPE SY-TITLE.Eventos ALV Grid Una de las grandes ventajas de los ALV’s es que nos permiten realizar varias tareas relacionadas a eventos. * *=====================================================* La variable G_USER_COMMAND tiene el valor por defecto USER_COMMAND. Y este evento “clic” es muy importante. puesto que nos permite interactuar con el registro que hemos seleccionado. como por ejemplo. También. De nuevo. ENDFORM. * *=====================================================* FORM USER_COMMAND USING R_UCOMM LIKE SY-UCOMM RS_SELFIELD TYPE SLIS_SELFIELD. DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT. Antes de empezar. 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. CHECK NOT RS_SELFIELD-TABNAME IS INITIAL. <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS.FORM INIT_LAYOUT. debemos declarar un nuevo Field-Symbol. READ TABLE T_PROGRAMAS INDEX RS_SELFIELD-TABINDEX 311 . " INIT_LAYOUT GS_LAYOUT-F2CODE guarda el nombre que le asignamos al código de función que en este caso es “FUNCION”. CASE R_UCOMM. WHEN 'FUNCION'. que hayamos seleccionado un registro.ASSIGNING <FS_PROGRAMAS>. 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. es decir. podemos continuar. CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-NOMBRE INTO MENSAJE SEPARATED BY SPACE. 312 . debemos primero asignar un nuevo valor a nuestra función creadora de ALV’s. es decir “FUNCION”. ENDCASE. Como era de esperarse. ENDFORM. Revisamos que la tabla RS_SELFIELD-TABNAME no esté vacía. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. "USER_COMMAND Declaramos una variable MENSAJE la cual va a contener el texto que queremos mostrar al hacer doble clic en una línea. Leemos la tabla interna con el índice del registro seleccionado. Cuando el código de función que hemos definido. a este parámetro le pasamos la variable G_USER_COMMAND. " F_GENERAR_LISTA_ALV = 1 = 2. G_PROGRAM = G_TITULO = SY-REPID. ENDFORM. G_TITULO = 'Lista de Programas'. = T_PROGRAMAS = ' ' = G_PROGRAM = G_TITULO = GS_LAYOUT = 'A' = I_FIELDCAT = GS_SORT[] = I_EVENTS I_CALLBACK_USER_COMMAND = G_USER_COMMAND Agregamos el parámetro I_CALLBACK_USER_COMMAND que permite hacer que funcionen los eventos. ENDIF. 313 .FORM F_GENERAR_LISTA_ALV. CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING I_BUFFER_ACTIVE I_CALLBACK_PROGRAM I_GRID_TITLE IS_LAYOUT I_SAVE IT_FIELDCAT IT_SORT IT_EVENTS TABLES T_OUTTAB EXCEPTIONS PROGRAM_ERROR OTHERS IF SY-SUBRC <> 0. EXIT. FORM INIT_LAYOUT.El parámetro I_SAVE = ‘A’ nos permite manejar las variantes. Cuando ejecutamos el programa. Hacemos lo siguiente. CLEAR L_FIELDCAT. 314 . bastará con hacer un doble clic en cualquier registro para ejecutar el evento. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. ENDFORM. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'. GS_LAYOUT-ZEBRA = ' '. " INIT_LAYOUT GS_LAYOUT-KEY_HOTSPOT indica que los campos pueden ser del tipo enlace. podemos entonces mejorar un poco el reporte. Si queremos hacer un solo clic. una celda. APPEND L_FIELDCAT TO T_FIELDCAT. L_FIELDCAT-SELTEXT_L = 'Id'. L_FIELDCAT-KEY = 'X'. 315 . los valores del campo ID_PROG. Para esto. pintar un registro. Como pueden ver. L_FIELDCAT-OUTPUTLEN = 5.L_FIELDCAT-FIELDNAME = 'ID_PROG'. lo cual indica que son campos claves para la activación con un clic por parte del usuario. Primero. necesitamos modificar un poco nuestra tabla interna. El L_FIELDCAT-KEY indica que este campo va a ser de tipo enlace. lo que vamos a hacer es pintar un registro de algún color. están subrayados. puede ser que alguna vez tengamos que pagar un ALV de colores. es decir. una fila. L_FIELDCAT-COL_POS = 1. Pintemos con colores Aunque esto no es muy común. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. 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. LINE_COLOR(4) TYPE C. 316 .*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. MODIFY T_PROGRAMAS FROM <FS_PROGRAMAS>. IF <FS_PROGRAMAS>-NOMBRE EQ 'RUBY'. END OF TY_PROGRAMAS. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. <FS_PROGRAMAS>-LINE_COLOR = 'C510'. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. Luego de obtener los datos. ID_PROG TYPE ZPROGRAMAS-ID_PROG. * *=====================================================* Agregamos un campo llamado LINE_COLOR que determina el color que queremos utilizar. debemos determinar que línea debe pintarse. ENDIF. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. FORM OBTENER_DATOS. 317 . así que espero les sirva también a ustedes. Finalmente. " OBTENER_DATOS Si el registro tiene el valor “RUBY” en el campo NOMBRE. es bastante sencillo. ENDFORM. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'. aunque no necesariamente útil. debemos indicar que queremos pintar una línea. FORM INIT_LAYOUT. pero ya me tocado hacerlo en algún proyecto. GS_LAYOUT-ZEBRA = ' '. ENDFORM.ENDLOOP. entonces pintamos la línea de verde utilizando el código C510. " INIT_LAYOUT Como ven. GS_LAYOUT-INFO_FIELDNAME = 'LINE_COLOR'. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. ID_PROG TYPE ZPROGRAMAS-ID_PROG. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. es decir. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. COLOR_CELL TYPE LVC_T_SCOL. Vamos a colorear celdas individuales en un ALV. pero simple de todos modos. ID_PROG TYPE ZPROGRAMAS-ID_PROG. TYPES: BEGIN OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS_AUX. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. una tabla interna que tiene como campo a otra tabla interna. END OF TY_PROGRAMAS_AUX. Primero. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. END OF TY_PROGRAMAS. esto porque al menos en el NetWeaver no se pueden hacer SELECT’s a una tabla interna con DEEP STRUCTURE. * *=====================================================* 318 . ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. tenemos que crear una tabla interna auxiliar y modificar un poco la tabla que teníamos. podemos pasar a algo un poco más complicado.Ahora que ya estamos felices con nuestro colorido ALV. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. y modificar el original agregando el campo COLOR_CELL que es en realidad. GS_LAYOUT TYPE SLIS_LAYOUT_ALV. I_EVENTS TYPE SLIS_T_EVENT. una tabla interna dentro de nuestra tabla interna. T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS_AUX. WA_COLOR TYPE LVC_S_SCOL.Debemos crear un nuevo TYPES. <FS_PROGRAMAS> LIKE LINE OF * *=====================================================* 319 . WA_COLOR y IT_COLOR nos sirven para almacenar algunos parámetros adicionales necesarios para el color de la celda. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT. I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV. IT_COLOR TYPE TABLE OF LVC_S_SCOL. * *=====================================================* Creamos una tabla interna basada en nuestro nuevo TYPE. Y agregamos un nuevo Field-Symbol. GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV. 320 . MOVE '6' TO WA_COLOR-COLOR-COL. luego. REFRESH IT_COLOR. LOOP AT T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. debemos hacer el SELECT a nuestra tabla interna auxiliar. No es dificil. <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. MOVE 'NOMBRE' TO WA_COLOR-FNAME. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. Nuestro código va a tener que cambiar un poco. FORM OBTENER_DATOS. 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. Primero. pero definitivamente quita más tiempo. MOVE-CORRESPONDING <FS_PROGRAMAS_AUX> TO <FS_PROGRAMAS>. IF <FS_PROGRAMAS_AUX>-NOMBRE EQ 'RUBY'.T_PROGRAMAS. 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. debemos utilizar los atributos del Layout.<FS_PROGRAMAS>-COLOR_CELL[] = IT_COLOR[]. 321 . ENDIF. GS_LAYOUT-ZEBRA = ' '. WA_COLOR tiene una tabla DEEP llamada COLOR). ENDLOOP. Apendamos WA_COLOR a la tabla IT_COLOR. GS_LAYOUT-KEY_HOTSPOT = 'X'. FORM INIT_LAYOUT. el INIT_LAYOUT también cambia. Asignamos el color que queremos para la celda (En este caso. " OBTENER_DATOS Debemos asignar el nombre del campo que se va a colorear a la tabla WA_COLOR-FNAME. en ese caso. Asignamos los registros de la tabla auxiliar a la tabla original y verificamos si el campo NOMBRE es igual a “RUBY”. 6 es rojo) a la tabla WA_COLOR-COLOR-COL (Como ven. GS_LAYOUT-F2CODE = 'FUNCION'. Finalmente. asignamos la tabla IT_COLOR al DEEP STRUCTURE COLOR_CELL de nuestra tabla original. GS_LAYOUT-COLTAB_FIELDNAME = 'COLOR_CELL'. indicándoles que ahora nos toca manejar campos y no registros. ENDFORM. puesto que como estamos utilizando una tabla interna para contener los colores. tenemos las siguientes. El ALV quedaría así. Ahora que ya sabemos como jugar con los eventos y con algunas propiedades del ALV. que además de ser Standard. muy rara vez tendremos que agregar botones adicionales. en este caso “COLOR_CELL”. " INIT_LAYOUT El campo COLTAB_FIELDNAME indica el tipo de evento que se va a aplicar a la columna de la lista. 322 . nos brinda toda la funcionalidad que podamos necesitar.ENDFORM. es decir. por lo cual. sería bueno que también conocieramos un poco de su barra de menús. Barra de Menús del ALV Entre las opciones standard que nos ofrece el ALV. pintar una celda. 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 . sentencias y liniamientos que se deben seguir para poder moldear procesos del mundo real.ABAP Orientado a Objetos Introducción Al igual que todos los productos de SAP. 330 . Es decir. con la POO nosotros podemos de una manera más clara y sencilla.6D. ¿Qué es la Orientación a Objetos? La Programación Orientada a Objetos. 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). el ABAP ha evolucionado para mejor. sino que por el contrario. A partir de la versión 4. Al decir que es una extensión. representar situaciones y/o procesos. a que el ABAP no ha sido reemplazado. ABAP cuenta con una extensión del lenguage. 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). nos estamos refiriendo. es una serie de reglas. Existen muchos puntos que debemos conocer primero y que son análogos en casi todos los lenguajes de programación orientados a objetos. que si bien en un escenario ideal.Sino tal vez un 60-40% sería suficiente (Dependiendo del caso. se utiliza una combinación de ambas fuerzas. no es imperativo desarrollar aplicaciones 100% OO. y por supuesto. Las clases se componen de dos capas. Las clases pueden ser definidas localmente en un programa o de modo global a 331 . Una vez que conozcamos estos conceptos. esto no ocurre en los escenarios reales. es simplemente un pedazo de código que define objetos y que define sus propiedades y métodos. y que puedan ser accesados a través de métodos públicos. • Clase: Una clase.. solo puede ser accedida por los objetos creados a partir de la misma clase. se guardan las propiedades de los objetos para poder encapsularlos. Por lo cual.. Muchas veces. En la capa privada. Conceptos básicos de la POO Los conceptos más importantes de la POO son. toda la programación debería ser orientada a objetos. La capa pública puede ser accedida por cualquier usuario. ABAP Objects no es la excepción. La capa privada. podremos ahondar en el ABAP Objects. claro está). una pública y otra privada (Que puede ser PRIVATE o PROTECTED). Cabe destacar. con ejemplos sencillos que ayuden a adquirir una base sólida para programar con este nuevo modelo de negocio. Un pequeño ejemplo de una clase. 332 . 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).través de la transacción SE24 (Class Builder). es necesario crear un objeto. Existen dos tipos de atributos. de instancia y estáticos. Las clases están compuestas por diferentes secciones: o Atributos Son los datos internos dentro de una clase. Pueden ser definidos como cualquier tipo de dato ABAP. Los atributos estáticos no requieren de un objeto para poder ser utilizados. Para utilizar atributos de instancia. o Métodos Son los procedimientos de la clase. 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). Las clases poseen dos fases importantes. De igual manera. Son muy parecidos a los módulos de función. *DEFINICIÓN DE UN MÉTODO ENDMETHOD. *IMPLEMENTACIÓN DE LA CLASE METHOD FACTORIAL. que lo único que hacen. Esto es útil cuando necesitamos que el objeto tenga un valor por defecto. 333 . PRIVATE SECTION.*-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION. nuestro objeto siempre tendrá un valor gracias al constructor. *DEFINICIÓN DE LA CLASE PUBLIC SECTION. "C_MATH DEFINITION * *-----------------------------------------------------* *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. Es decir. si un usuario no asigna un valor a la hora de ejecutar el programa. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS. si es que el programa no se lo asigna. "FACTORIAL "C_MATH IMPLEMENTATION * *-----------------------------------------------------* Las clases pueden utilizar los llamados Constructores. ENDCLASS. *SECCIÓN PÚBLICA DE LA CLASE METHODS: *MÉTODOS FACTORIAL. es inicializar un objeto con valores en el mismo momento que está siendo creado. *DEFINICIÓN DE UN MÉTODO ENDMETHOD. *DEFINICIÓN DE LA CLASE PUBLIC SECTION.*-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION. WRITE:/ NAME. *ENVIAMOS EL PARÁMETRO AL CONSTRUCTOR DE LA CLASE ENDMETHOD. METHOD FACTORIAL. ENDCLASS. "FACTORIAL "C_MATH IMPLEMENTATION "CONSTRUCTOR * *-----------------------------------------------------* Las clases pueden ser definidas utilizando Herencias. "C_MATH DEFINITION * *-----------------------------------------------------* *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. FACTORIAL. *IMPLEMENTACIÓN DE LA CLASE METHOD CONSTRUCTOR. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS. que no es más que crear una clase a partir de otra existente. Esto nos sirve para 334 . *SECCIÓN PÚBLICA DE LA CLASE METHODS: *MÉTODOS CONSTRUCTOR IMPORTING NAME TYPE STRING. PRIVATE SECTION. una se creó heredando características de la primera. * *-----------------------------------------------------* "C_SUPERMATH DEFINITION * *-----------------------------------------------------* 335 . y podemos crear otra clase que herede de nuestra clase factura. Así. *Definición de la clase *-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION INHERITING FROM C_SUPERMATH . ENDCLASS. pero que además. es llamada una Sub Clase. *-----------------------------------------------------* * CLASS C_SUPERMATH DEFINITION CLASS C_SUPERMATH DEFINITION. *Sección Pública de la clase METHODS: *Métodos FACTORIAL. tenemos dos clases. nos de la posibilidad de obtener la cuenta contrato de dicha factura. es llamada una Super Clase y la que ha heredado dichas funcionalidades. nosotros podemos crear una clase que obtenga el número de factura de un pedido. Es decir. haciéndolas distintas e independientes. *Hereda de C_SUPERMATH PUBLIC SECTION. La clase que brinda su funcionalidad.agregar funcionalidades que queremos que se encuentren separadas. Una Sub Clase se define de la siguiente manera. pero le agregó una funcionalidad adicional. *IMPLEMENTACIÓN DE LA CLASE METHOD FACTORIAL. lo hacemos de la siguiente manera. No existe un límite acerca de la cantidad de objetos que se pueden crear a partir de una clase. *Creamos e instanciamos un objeto *con referencia al tipo que creamos. *Definimos un tipo de dato que se *referiencia a la clase C_MATH DATA DESCR_REF TYPE REF TO C_MATH. por lo cual.PRIVATE SECTION. son copias que poseen la misma funcionalidad de la clase que los creó. "FACTORIAL "C_MATH IMPLEMENTATION * *-----------------------------------------------------* • Objeto: Los objetos son instancias de una clase. *DEFINICIÓN DE UN MÉTODO ENDMETHOD. Para instanciar un objeto. Cada objeto creado a partir de una clase. ENDCLASS. "C_MATH DEFINITION *-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. no hay preocuparse. CREATE OBJECT DESCR_REF. se comporta como un elemento completamente independiente de los demás. *SECCIÓN PRIVADA DE LA CLASE ENDCLASS. Es decir. 336 . lo cual no está mal. Tanto en código como con el Generador de Clases (SE24).Como programar en ABAP Objects Hasta ahora. Factorial REPORT ZDUMMY_PRIMER_PROGRAMA. "FACTORIAL DEFINITION 337 . vamos a ver un ejemplo reescritos en ABAP Objects. METHODS: SET_FACT IMPORTING NUM TYPE I. ENDCLASS. pero lo mejor es utilizar las nuevas tecnologías. *-----------------------------------------------------* * CLASS FACTORIAL DEFINITION *-----------------------------------------------------* CLASS C_FACTORIAL DEFINITION. SELECTION-SCREEN END OF SCREEN 101. los ejemplos que hemos desarrollado. PRIVATE SECTION. PARAMETERS NUMBER TYPE I. DATA FACT TYPE I. por lo tanto. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. CLASS-METHODS: MAIN. fueron escritos utilizando el ABAP tradicional. GET_RESULT RETURNING VALUE(FACT) TYPE I. PUBLIC SECTION. C_FACTORIAL=>MAIN( ). EXIT. IF SY-SUBRC NE 0. ENDCLASS. ME->FACT. DO NUM TIMES.*-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION. IF NUM GT 0. ENDMETHOD. CREATE OBJECT MY_OBJ. ENDMETHOD. ENDIF. ENDDO. CALL METHOD MY_OBJ->GET_RESULT. START-OF-SELECTION. FACT = FACT * SY-INDEX. WRITE: 'El Factorial es: '. "GET_RESULT "FACTORIAL IMPLEMENTATION "SET_FACT "MAIN 338 . METHOD GET_RESULT. METHOD SET_FACT. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). FACT = 1. DATA MY_OBJ TYPE REF TO C_FACTORIAL. ENDIF. METHOD MAIN. ENDMETHOD. CALL SELECTION-SCREEN '101' STARTING AT 10 10. Además. CLASS-METHODS: MAIN. ENDCLASS. En la sección pública. SELECTION-SCREEN END OF SCREEN 101. declaramos dos métodos. "FACTORIAL DEFINITION Creamos nuestra clase C_FACTORIAL. extraño e innecesario. GET_RESULT RETURNING VALUE(FACT) TYPE I. un método de instacia. es decir. DATA FACT TYPE I. Revisemos un poco el código antes de ejecutarlo. Declaramos un SELECTION-SCREEN pero utilizando un tipo ventana. SET_FACT que recibe un 339 . esto para poder llamarlo desde nuestra clase.Este código se puede ver un poco complicado. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. PUBLIC SECTION. METHODS: SET_FACT IMPORTING NUM TYPE I. definimos un CLASS-METHOD. PRIVATE SECTION. PARAMETERS NUMBER TYPE I. *-----------------------------------------------------* * CLASS FACTORIAL DEFINITION * *-----------------------------------------------------* CLASS C_FACTORIAL DEFINITION. pero creanme que con el tiempo uno se acostumbra y la verdad es que es lo mejor programar así. METHOD MAIN. EXIT. que es la que va a tener el resultado del factorial y es la variable que va a imprimir GET_RESULT. METHOD SET_FACT. ENDIF. ENDIF. DO NUM TIMES. IF NUM GT 0. "GET_RESULT "FACTORIAL IMPLEMENTATION "SET_FACT "MAIN Implementamos nuestra clase. ENDDO. En la sección privada. IF SY-SUBRC NE 0. FACT = FACT * SY-INDEX. ENDCLASS. *-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION * *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION.parámetro NUM y GET_RESULT que retorna el valor final del programa. agregando el código a los métodos. METHOD GET_RESULT. ENDMETHOD. ENDMETHOD. declaramos una variable llamada FACT. 340 . CALL SELECTION-SCREEN '101' STARTING AT 10 10. ME->FACT. FACT = 1. ENDMETHOD. WRITE: 'El Factorial es: '. Llamamos al método SET_FACT pasando el valor del parámetro obtenido en la ventana del SELECTION-SCREEN.En el método MAIN. donde ME equivale a C_FACTORIAL. CREATE OBJECT MY_OBJ. esto es porque este método no recibe parámetros. Llamamos al método estático MAIN. 341 . DATA MY_OBJ TYPE REF TO C_FACTORIAL. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). por lo cual necesita obtener el valor de la misma clase. C_FACTORIAL=>MAIN( ). En el método GET_RESULT imprimimos el valor de la variable FACT. Como se darán cuenta. podemos escribirlo así ME->FACT. Felizmente. pero como la variable está en la sección privada. START-OF-SELECTION. con lo cual quedaría así C_FACTORIAL->FACT. y para no escribir tanto. entonces necesitamos acceder a ella definiendo el nombre de la clase y la variable. y lo creamos. declaramos un objeto de la clase C_FACTORIAL. En el método SET_FACT realizamos el algoritmo para determinar el factorial. utilizamos ME->FACT para llamar a la variable. Llamamos al método GET_RESULT para mostrar el resultado. llamamos a nuestra pantalla para poder capturar el valor ingresado por el usuario. CALL METHOD MY_OBJ->GET_RESULT. así que veamos que pasa si ingresamos 13. 342 .Por cuestiones de tamaño de almacenamiento de la variable. los números pueden ir desde el 1 hasta el 12. NET. nos envía un error personalizado. en donde y hasta como podríamos resolverlo. DATA: FACT TYPE I. Esta ventana. El cual funciona como un TRY-CATCH en Java o . En esta caso. nos indica porque se ha producido el error. 343 . puesto que el tamaño de la variable que utilizamos no fue lo suficientemente grande como para poder almacenar el valor del factorial. vamos a utilizar un comando llamado CATCH SYSTEMEXCEPTION. un error grave en la programación). CLASS C_FACTORIAL DEFINITION. PRIVATE SECTION. CLASS-METHODS: MAIN. y lo que hace es simplemente intentar ejecutar una sentencia y si no puede. FLAG TYPE C. vamos a utilizar una pequeña artimaña para que nuestro programa siga funcionando a pesar de este error.En este caso. METHODS: SET_FACT IMPORTING NUM TYPE I. es la de un ShortDump (Es decir. se ha producido un error. ENDCLASS. cuando. PUBLIC SECTION. que permite que el programa siga funcionando a pesar del error. debemos hacer unas cuantas modificaciones al programa. "FACTORIAL DEFINITION Declaramos una variable llamada FLAG que nos va a servir al momento de mostrar el mensaje de resultado. La imagen que vemos. para ello. Para esto. GET_RESULT RETURNING VALUE(FACT) TYPE I. METHOD SET_FACT. ENDCATCH. IF SY-SUBRC EQ 5. ENDIF. limpiamos nuestra variable FLAG y utilizamos un CATCH SYSTEM-EXCEPTIONS. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. DO NUM TIMES. FACT = 1. IF NUM GT 0. entonces limpiamos la variable FACT y llenamos con “X” la variable FLAG. Obviamente. que significa que cualquier error de tipo Overflow (valor más grande que el tamaño de variable). CLEAR FLAG. "SET_FACT Dentro del método SET_FACT. EXIT. 344 . FACT = 0. FACT = FACT * SY-INDEX. En el caso de que el SY-SUBRC sea igual a 5. ENDDO. en este caso el ARITHMETIC_ERRORS. ENDIF. ENDMETHOD. va a lanzar un SY-SUBRC igual a 5 en vez de una pantalla de ShortDump. FLAG = 'X'. salimos del método utilizando la sentencia EXIT. ingrese valores del 1 al 12'. WRITE: 'Error. Ahora. ELSE. si tiene el valor “X”. IF FLAG EQ SPACE. preguntamos si la variable FLAG está vacía o tiene el valor “X”.METHOD GET_RESULT. ENDMETHOD. gracias a lo cual podríamos obtener el Factorial de un número desde cualquier programa. imprimimos el valor del factorial. 345 . ENDIF. veamos el mismo ejemplo pero utilizando el Generador de Clases (SE24). imprimimos un mensaje de advertencia. "GET_RESULT En el método GET_RESULT. Si está vacía. WRITE: 'El Factorial es: '. ME->FACT. 346 . debemos presionar el botón Parameters (Parámetros) .Primero. nos dirigimos a la pestaña Methods (Métodos). Luego. un Visibility (Visibilidad) 0 Private (Privado). Declaramos dos métodos. Ambas variables tiene un Level (Nivel) 0 Instance Attribute (Atributo de Instacia). 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). SET_FACT y GET_RESULT. Para asignar los parámetros. 347 . debemos posicionarnos sobre cada uno de ellos y presionar el botón Code . GET_RESULT tiene el parámetro FACT de tipo RETURNING. Para poder asignarles código a los métodos.SET_FACT tiene el parámetro NUM de tipo IMPORTING. 348 . endmethod. ENDCATCH. FACT = 1. FACT = 0. endmethod. solo nos queda grabar. pero claro. CLEAR FLAG. WRITE: 'Error. presionamos el botón Test o presionamos F8 . ME->FACT. DO NUM TIMES. IF FLAG EQ SPACE. ENDIF. WRITE: 'El Factorial es: '. method GET_RESULT. ingrese valores del 1 al 12'.Escribimos los códigos para cada método. FLAG = 'X'. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. 349 . FACT = FACT * SY-INDEX. La clase está lista para ser utilizada. Con esto. lo mejor es probarlo antes. activar. ENDIF. EXIT. ENDDO. IF SY-SUBRC EQ 5. ELSE. ENDIF. IF NUM GT 0. Para esto. method SET_FACT. . De vuelta en la pantalla principal. ejecutamos el método 350 .Como sabemos que SET_FACT es el método que recibe el valor ingreado por el usario. Ingresamos un valor de prueba y presionamos el botón Execute (Ejecutar) o presionamos F8 GET_RESULT. lo ejecutamos presionando el botón Execute Method (Ejecutar Método) . SELECTION-SCREEN END OF SCREEN 101. simplemente debemos retroceder para ver el resultado. Listo. PARAMETERS NUMBER TYPE I. ya podemos utilizar nuestra nueva clase en un programa.A pesar de que el valor de FACT aparece como 0. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. 351 . ahora. REPORT ZDUMMY_PRIMER_PROGRAMA. EXIT. CREATE OBJECT MY_OBJ. 352 . CALL SELECTION-SCREEN '101' STARTING AT 10 10. ENDIF. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). IF SY-SUBRC NE 0. Ejecutamos y veremos que el resultado es el mismo. aunque el código es mucho más corto y reutilizable.START-OF-SELECTION. DATA MY_OBJ TYPE REF TO ZFACTORIAL. CALL METHOD MY_OBJ->GET_RESULT. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. GT_SORT TYPE LVC_T_SORT. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. * *=====================================================* * *=====================================================* 353 . pero ahora veremos como se hace con ABAP Objects. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ID_PROG TYPE ZPROGRAMAS-ID_PROG. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. GT_FIELDCAT TYPE LVC_T_FCAT. END OF TY_PROGRAMAS. GS_LAYOUT TYPE LVC_S_LAYO. ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. GS_VARIANT TYPE DISVARIANT.Componentes Orientados a Objetos Crear un ALV Grid OO Ya vimos como crear un ALV. 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 ). GRID1 TYPE REF TO CL_GUI_ALV_GRID. PERFORM LLAMAR_ALV. *&----------------------------------------------------* *& Form cargar_datos * *&----------------------------------------------------* FORM CARGAR_DATOS. X_SAVE. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM FILL_CATALOG. PERFORM FILL_LAYOUT. " cargar_datos * *=====================================================* * *=====================================================* 354 . PERFORM CARGAR_DATOS. CALL SCREEN 0100. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER.*=====================================================* * DECLARACION DE VARIABLES DATA: MYCONTAINER TYPE SCRFNAME VALUE 'CUSTOM_ALV'. ENDFORM. GS_FIELDCAT-COL_POS = 2. APPEND GS_FIELDCAT TO GT_FIELDCAT. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. " fill_layout *&----------------------------------------------------* *& Form fill_catalog * *&----------------------------------------------------* FORM FILL_CATALOG. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. GS_LAYOUT-SEL_MODE = 'A'. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. 355 . GS_FIELDCAT-FIELDNAME = 'ID_PROG'. CLEAR GS_FIELDCAT. CLEAR GS_FIELDCAT. APPEND GS_FIELDCAT TO GT_FIELDCAT. GS_FIELDCAT-REPTEXT = 'Nombre Programa'. GS_FIELDCAT-COL_POS = 1. GS_FIELDCAT-OUTPUTLEN = 15.*&----------------------------------------------------* *& Form fill_layout * *&----------------------------------------------------* FORM FILL_LAYOUT. GS_FIELDCAT-OUTPUTLEN = 5. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. ENDFORM. GS_FIELDCAT-REPTEXT = 'Id'. 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 EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR ENDIF. CREATE OBJECT GRID1 EXPORTING I_PARENT = CUSTOM_CONTAINER. CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_VARIANT I_SAVE I_DEFAULT IS_LAYOUT CHANGING IT_FIELDCATALOG = GT_FIELDCAT IT_SORT IT_OUTTAB = GT_SORT[] = T_PROGRAMAS[]. = GS_VARIANT = X_SAVE = 'X' = GS_LAYOUT = 1 = 2 = 3 = 4 = MYCONTAINER LIFETIME_DYNPRO_DYNPRO_LINK = 5. 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 EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR ENDIF. CREATE OBJECT GRID1 EXPORTING I_PARENT = CUSTOM_CONTAINER. CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_VARIANT I_SAVE I_DEFAULT IS_LAYOUT CHANGING IT_FIELDCATALOG = GT_FIELDCAT IT_SORT IT_OUTTAB = GT_SORT[] = T_PROGRAMAS[]. = GS_VARIANT = X_SAVE = 'X' = GS_LAYOUT = 1 = 2 = 3 = 4 = MYCONTAINER LIFETIME_DYNPRO_DYNPRO_LINK = 5. 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 .. no es muy útil que digamos puesto que no hace. claro está... Agregamos un nuevo campos a nuestro TYPE TY_PROGRAMAS y creamos un nuevo TYPE llamado TY_NOMBRE.. nos vamos al Menu Painter (SE41) y agregamos un nuevo botón. NOM_PROG TYPE ZPROGRAMAS-NOM_PROG. ID_PROG TYPE ZPROGRAMAS-ID_PROG. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. pero al mismo tiempo debemos modificar su estructura (Solamente dentro de nuestro programa.. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE.Agregar validaciones y eventos Si bien el programa funciona.nada.Así que vamos a agregar algunas cosas adicionales.. Debemos llamar a la clase LCL_EVENT_RECIEVER. * *=====================================================* 367 .) CLASS LCL_EVENT_RECEIVER DEFINITION DEFERRED.. Primero. LT_F4 TYPE LVC_T_F4 WITH HEADER LINE. NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. 368 . *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. T_STABLE TYPE STANDARD TABLE OF LVC_S_STBL WITH HEADER LINE. END OF TY_NOMBRE. T_NOMBRE TYPE STANDARD TABLE OF TY_NOMBRE. CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP. ID TYPE ZLENGUAJES_PROG-ID. GT_FIELDCAT TYPE LVC_T_FCAT. TYPES: BEGIN OF TY_NOMBRE. GS_VARIANT TYPE DISVARIANT. ID TYPE ZPROGRAMAS-ID. END OF TY_PROGRAMAS. * *=====================================================* T_NOMBRE nos sirve para crear una ayuda de búsqueda personalizada. GT_SORT TYPE LVC_T_SORT. Agregamos algunas tablas internas. GS_LAYOUT TYPE LVC_S_LAYO.ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO. RETURN_TAB TYPE STANDARD TABLE OF DDSHRETVAL WITH HEADER LINE. LT_F4 nos sirve para determinar que campos van a tener asignada una ayuda de búsqueda. * *=====================================================* EVENT_RECIEVER nos permite crear una referencia para llamar eventos en el ALV. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. EVENT_RECEIVER TYPE REF TO LCL_EVENT_RECEIVER. *=====================================================* * DECLARACION DE VARIABLES DATA: MYCONTAINER TYPE SCRFNAME VALUE 'CUSTOM_ALV'. L_VALID indica si la operación es válida o no. 369 . Agregamos algunas variables. GRID1 TYPE REF TO CL_GUI_ALV_GRID. W_ERROR nos indica si hay algún error en la modificación de datos. RETURN_TAB es la tabla que nos devuelve el valor seleccionado por la función para crear ayudas de búsqueda. L_VALID(1) TYPE C. W_ERROR TYPE C. T_STABLE nos permite que el ALV mantenga su posición al momento de actualizar los datos. X_SAVE. *-----------------------------------------------------* * CLASS LCL_EVENT_RECEIVER DEFINITION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER DEFINITION. <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. * *=====================================================* Redefinimos la clase LCL_EVENT_RECIEVER. METHODS: HANDLE_DATA_CHANGED FOR EVENT DATA_CHANGED OF CL_GUI_ALV_GRID IMPORTING ER_DATA_CHANGED. ENDCLASS. HANDLE_F4_HELP FOR EVENT ONF4 OF CL_GUI_ALV_GRID IMPORTING E_FIELDNAME ES_ROW_NO ER_EVENT_DATA. 370 . *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_NOMBRE> LIKE LINE OF T_NOMBRE. PUBLIC SECTION. 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. "LCL_EVENT_RECEIVER DEFINITION Definimos dos métodos.Agregamos algunos Field-Symbols. METHOD HANDLE_DATA_CHANGED. ENDMETHOD. ENDCLASS. 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 ). Dentro del método HANDLE_F4_HELP llamamos al FORM HANDEL_ONF4. *&----------------------------------------------------* *& Form cargar_datos * *&----------------------------------------------------* FORM CARGAR_DATOS. "HANDLE_F4_HELP "LCL_EVENT_RECEIVER IMPLEMENTATION "HANDLE_DATA_CHANGED Dentro del método HANDLE_DATA_CHANGED llamamos al FORM DATA_CHANGED. METHOD HANDLE_F4_HELP. = ‘X’.*-----------------------------------------------------* * CLASS lcl_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER IMPLEMENTATION. PERFORM DATA_CHANGED USING ER_DATA_CHANGED. ER_EVENT_DATA->M_EVENT_HANDLED especificamos que queremos activar el evento. ENDMETHOD. 371 . ER_EVENT_DATA->M_EVENT_HANDLED = 'X'. PERFORM HANDLE_ONF4 USING E_FIELDNAME ES_ROW_NO. *&----------------------------------------------------* *& Form llamar_alv * *&----------------------------------------------------* FORM LLAMAR_ALV. GS_FIELDCAT-EDIT = 'X'.SELECT ID NOMBRE INTO TABLE T_NOMBRE FROM ZLENGUAJES_PROG. por lo que agregamos EDIT para que pueda modificarse y F4AVAILABL para que acepte la ayuda de búsqueda dinámica. 372 . APPEND GS_FIELDCAT TO GT_FIELDCAT. GS_FIELDCAT-OUTPUTLEN = 15. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-COL_POS = 3. GS_FIELDCAT-FIELDNAME = 'NOMBRE'. GS_FIELDCAT-REPTEXT = 'Nombre Lenguaje'. ENDFORM. CLEAR GS_FIELDCAT. GS_FIELDCAT-F4AVAILABL = 'X'. " cargar_datos Agregamos un nuevo select. solamente vamos a modificar un campo. Dentro del catálogo. esta vez a ZLENGUAJES_PROG para poder obtener los valores necesarios para nuestra ayuda de búsqueda dinámica. APPEND LT_F4. LT_F4-GETBEFORE = 'X' . LT_F4-CHNGEAFTER = 'X' . = 1 = 2 = 3 = 4 = MYCONTAINER LIFETIME_DYNPRO_DYNPRO_LINK = 5. CREATE OBJECT EVENT_RECEIVER. SET HANDLER EVENT_RECEIVER>HANDLE_DATA_CHANGED FOR GRID1. SET HANDLER EVENT_RECEIVER->HANDLE_F4_HELP FOR GRID1.IF CUSTOM_CONTAINER IS INITIAL. CREATE OBJECT GRID1 EXPORTING I_PARENT = CUSTOM_CONTAINER. 373 . CALL METHOD GRID1->REGISTER_F4_FOR_FIELDS EXPORTING IT_F4 = LT_F4[]. LT_F4-REGISTER = 'X' . CREATE OBJECT CUSTOM_CONTAINER EXPORTING CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR ENDIF. LT_F4-FIELDNAME = 'NOMBRE'. ENDFORM. ENDIF. = GS_VARIANT = X_SAVE = 'X' = GS_LAYOUT CALL METHOD GRID1->SET_READY_FOR_INPUT EXPORTING I_READY_FOR_INPUT = 1. CALL METHOD GRID1->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_VARIANT I_SAVE I_DEFAULT IS_LAYOUT CHANGING IT_FIELDCATALOG = GT_FIELDCAT IT_SORT IT_OUTTAB = GT_SORT[] = T_PROGRAMAS[]. CALL METHOD GRID1->REGISTER_EDIT_EVENT EXPORTING I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED.IF SY-BATCH IS INITIAL. Establecemos los eventos utilizando el comando SET HANDLER. con el campo que tendrá la ayuda de búsqueda dinámica. " llamar_alv Creamos el objeto EVENT_RECIEVER para poder asignar los eventos al ALV. Llenamos la tabla LT_F4. 374 . OK_CODE = SY-UCOMM. CALL METHOD GRID1->CHECK_CHANGED_DATA IMPORTING E_VALID = L_VALID. " USER_COMMAND_0100 INPUT Agregamos el código de función SAVE.La variable SY-BATCH nos indica si estamos ejecutando el programa en fondo o en modo directo. SET SCREEN 0. entonces registramos el evento de modificación. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. ENDMODULE. CLEAR SY-UCOMM. 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. LEAVE SCREEN. si es en modo directo. WHEN 'SAVE'. IF L_VALID EQ 'X'. ENDIF. CASE OK_CODE. 375 . *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. PERFORM GRABAR_DATOS. DATA: OK_CODE TYPE SY-UCOMM. LS_MOD_CELLS TYPE LVC_S_MODI. LS_CELLS TYPE LVC_S_MODI. DATA: L_NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. = LS_MOD_CELLS-ROW_ID I_FIELDNAME = LS_MOD_CELLS-FIELDNAME I_FIELDNAME = LS_MOD_CELLS-FIELDNAME 376 . CASE LS_MOD_CELLS-FIELDNAME. IF L_NOMBRE IS INITIAL.*&----------------------------------------------------* *& Form data_changed * *&----------------------------------------------------* FORM DATA_CHANGED USING RR_DATA_CHANGED TYPE REF TO CL_ALV_CHANGED_DATA_PROTOCOL. LOOP AT RR_DATA_CHANGED->MT_GOOD_CELLS INTO LS_MOD_CELLS. WHEN 'NOMBRE'. DATA: W_NEW. CALL METHOD RR_DATA_CHANGED->GET_CELL_VALUE EXPORTING I_ROW_ID IMPORTING E_VALUE CALL METHOD RR_DATA_CHANGED->ADD_PROTOCOL_ENTRY EXPORTING I_MSGID I_MSGNO I_MSGTY I_MSGV1 = '0K' = '000' = 'E' = 'Seleccione algún nombre' = L_NOMBRE. I_FIELDNAME = 'ID' = '0K' = '000' = 'E' = 'Nombre ingresado no existe' = LS_MOD_CELLS-ROW_ID. ENDFORM. I_FIELDNAME = LS_MOD_CELLS-FIELDNAME W_ERROR = 'X'. ELSE. es decir a los campos que han cambiado de 377 . CALL METHOD RR_DATA_CHANGED->ADD_PROTOCOL_ENTRY EXPORTING I_MSGID I_MSGNO I_MSGTY I_MSGV1 I_ROW_ID ELSE. Hacemos un LOOP a RR_DATA_CHANGED- >MT_GOOD_CELLS. READ TABLE T_NOMBRE WITH KEY NOMBRE = L_NOMBRE ASSIGNING <FS_NOMBRE>.I_ROW_ID W_ERROR = 'X'. IF SY-SUBRC NE 0. "data_changed = LS_MOD_CELLS-ROW_ID = <FS_NOMBRE>-ID. ENDLOOP. ENDCASE. CALL METHOD RR_DATA_CHANGED->MODIFY_CELL EXPORTING I_ROW_ID I_VALUE ENDIF. ENDIF. = LS_MOD_CELLS-ROW_ID. valor. llamamos al método MODIFY_CELL para modificar el campo ID (Puesto que nosotros hemos modificado el campo NOMBRE. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD VALUE_ORG TABLES VALUE_TAB RETURN_TAB EXCEPTIONS PARAMETER_ERROR = 1 NO_VALUES_FOUND = 2 OTHERS = 3. = T_NOMBRE = RETURN_TAB = 'NOMBRE' = 'S' 378 . Si está vacío. 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. pero necesitamos que a su vez se modifique también el campo ID). WHEN 'NOMBRE'. CASE P_E_FIELDNAME. en caso contrario leemos la tabla interna T_NOMBRE para validar que el valor exista. *&----------------------------------------------------* *& Form handle_onf4 * *&----------------------------------------------------* FORM HANDLE_ONF4 USING P_E_FIELDNAME P_ES_ROW_NO STRUCTURE LVC_S_ROID. Si no hay más problemas. ENDIF. "handle_onf4 Llamamos al método F4IF_INT_TABLE_VALUE_REQUEST para poder mostrar la ayuda de búsqueda dinámica. *&----------------------------------------------------* *& Form grabar_datos * *&----------------------------------------------------* FORM GRABAR_DATOS. <FS_PROGRAMAS>-NOMBRE = RETURN_TAB-FIELDVAL. UPDATE ZPROGRAMAS SET ID = <FS_PROGRAMAS>-ID WHERE ID_PROG EQ <FS_PROGRAMAS>-ID_PROG. Llamamos al método REFRESH_TABLE_DISPLAY para refrescar el contenido del ALV. ENDCASE. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE ID NE SPACE. CALL METHOD GRID1->REFRESH_TABLE_DISPLAY EXPORTING IS_STABLE = T_STABLE. READ TABLE T_NOMBRE WITH KEY NOMBRE = RETURN_TAB-FIELDVAL ASSIGNING <FS_NOMBRE>. 379 .IF NOT RETURN_TAB[] IS INITIAL. READ TABLE T_PROGRAMAS INDEX P_ES_ROW_NO-ROW_ID ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID = <FS_NOMBRE>-ID. ENDFORM. READ TABLE RETURN_TAB INDEX 1. Grabamos. ELSE.IF SY-SUBRC EQ 0. que tengan un valor en el campo ID. activamos y ejecutamos. " GRABAR_DATOS Recorremos todos los registros de nuestra tabla interna. COMMIT WORK. ENDIF. ROLLBACK WORK. 380 . luego utilizamos un UPDATE para actualizar los valores de la Base de Datos. ENDFORM. ENDLOOP. * *=====================================================* 381 . LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. TYPES: BEGIN OF TY_HEADER. END OF TY_PROGRAMAS. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. REPORT ZDUMMY_PRIMER_PROGRAMA. END OF TY_HEADER. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. Este tipo de reporte no es muy utilizado.Crear un ALV Tree OO Un ALV Tree es un tipo de reporte jerárquico. en donde un nodo principal agrupa subnodos u hojas. Este es el código. pero de todos modos es muy intersante y vale la pena revisarlo. * *=====================================================* * *=====================================================* * *=====================================================* 382 . *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. L_HIERARCHY_HEADER TYPE TREEV_HHDR. T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. T_HEADER TYPE STANDARD TABLE OF TY_HEADER.*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. <FS_TREE> LIKE LINE OF T_PROGRAMAS. <FS_HEADER> LIKE LINE OF T_HEADER. GT_FIELDCAT_TREE TYPE LVC_T_FCAT. DELETE ADJACENT DUPLICATES FROM T_HEADER. ENDLOOP. CALL SCREEN 0100. ENDFORM.*=====================================================* * START-OF-SELECTION START-OF-SELECTION. <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. SORT T_HEADER. PERFORM CARGAR_DATOS. APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. PERFORM INIT_TREE. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. " CARGAR_DATOS * *=====================================================* 383 . WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. " USER_COMMAND_0100 INPUT 384 .*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. CLEAR SY-UCOMM. SET PF-STATUS '100'. SET TITLEBAR '100'. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. ENDMODULE. ENDCASE. CASE OK_CODE. OK_CODE = SY-UCOMM. ENDMODULE. LEAVE SCREEN. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 = LIFETIME_DYNPRO_DYNPRO_LINK = 5. L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. DATA: L_TREE_CONTAINER_NAME(30) TYPE C.*&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. CREATE OBJECT G_ALV_TREE EXPORTING PARENT NODE_SELECTION_MODE ITEM_SELECTION NO_HTML_HEADER NO_TOOLBAR EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR = 1 = 2 = 3 = G_CUSTOM_CONTAINER = = '' = 'X' = '' CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE 385 . DATA: GS_FIELDCAT TYPE LVC_S_FCAT. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. GS_FIELDCAT-OUTPUTLEN = 20. ENDFORM. PERFORM CREATE_HIERARCHY. = 4 = 6 = 7. GS_FIELDCAT-SCRTEXT_S = 'Nom. Programa'. ILLEGAL_NODE_SELECTION_MODE = 5 PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER.LIFETIME_ERROR FAILED ILLEGAL_COLUMN_NAME PERFORM FILL_CATALOG_TREE. CALL METHOD G_ALV_TREE->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_HIERARCHY_HEADER = L_HIERARCHY_HEADER CHANGING IT_OUTTAB IT_FIELDCATALOG = T_TREE[] = GT_FIELDCAT_TREE. GS_FIELDCAT-COL_POS = 1. " INIT_TREE *&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. 386 . CLEAR GS_FIELDCAT. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. P_HIERARCHY_HEADER-HEADING = 'Código'(300). GS_FIELDCAT-COL_POS = 2. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. L_NEXT_KEY TYPE LVC_NKEY. DATA: L_ROOT_KEY TYPE LVC_NKEY. P_HIERARCHY_HEADER-WIDTH = 60. ENDFORM. CLEAR GS_FIELDCAT. GS_FIELDCAT-OUTPUTLEN = 15. ENDFORM.APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. 387 . "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. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. CLEAR P_HIERARCHY_HEADER. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. ENDFORM. ENDLOOP. 388 . ENDLOOP. CLEAR L_ROOT_KEY. CLEAR L_NEXT_KEY. PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. HEADER = <FS_HEADER>-LENGUAJE. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. "CREATE_HIERARCHY *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY.L_LAST_KEY TYPE LVC_NKEY. W_MENGE_TEXT(13) TYPE C. LOOP AT T_HEADER ASSIGNING <FS_HEADER>. PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. HEADER TYPE STRING. CLEAR L_ROOT_KEY. DATA: L_NODE_TEXT TYPE LVC_VALUE. = L_NEXT_KEY. LS_TREE TYPE TY_PROGRAMAS. "ADD_NODE = = L_NODE_TEXT = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME. L_NODE_TEXT = EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP I_NODE_TEXT IS_OUTTAB_LINE IMPORTING E_NEW_NODE_KEY ENDFORM. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP IS_OUTTAB_LINE IMPORTING E_NEW_NODE_KEY = L_LAST_KEY. CALL METHOD G_ALV_TREE->ADD_NODE *&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. = = T_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD 389 . END OF TY_PROGRAMAS. 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. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. * *=====================================================* Declaramos dos TYPE’s. T_HEADER TYPE STANDARD TABLE OF * *=====================================================* 390 . END OF TY_HEADER. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS.ENDFORM. "ADD_LEAF Revisemos el código paso a paso. TYPES: BEGIN OF TY_HEADER. T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE. GT_FIELDCAT_TREE TYPE LVC_T_FCAT. Declaramos algunas tablas internas. <FS_HEADER> LIKE LINE OF * *=====================================================* 391 . *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS.TY_HEADER. GT_FIELDCAT_TREE es el catálogo del ALV. T_HEADER es la cabecera del ALV. L_HIERARCHY_HEADER TYPE TREEV_HHDR. * *=====================================================* Declaramos algunas variables. G_CUSTOM_CONTAINER que es un contenedor para el ALV y L_HIERARCHY_HEADER que sirve para definir la cabecera. OK_CODE para guardar el código de función. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. G_ALV_TREE que es un objeto de la clase CL_GUI_ALV_TREE. T_PROGRAMAS que guarda los datos del ALV. T_TREE que es una tabla intermedia para mostrar los datos del ALV. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. 392 . <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE. PERFORM INIT_TREE. <FS_TREE> LIKE LINE OF T_PROGRAMAS. llamamos a la pantalla 100. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>.T_HEADER. CALL SCREEN 0100. APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. * *=====================================================* Llamamos dos FORM’s CARGAR_DATOS e INIT_TREE. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. Declaramos algunos Field-Symbols. PERFORM CARGAR_DATOS. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. ENDMODULE. SORT T_HEADER. CLEAR SY-UCOMM. DELETE ADJACENT DUPLICATES FROM T_HEADER. Luego asignamos el campo LENGUAJE a la tabla T_HEADER y eliminamos los registros duplicados.ENDLOOP. SET TITLEBAR '100'. *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. " CARGAR_DATOS Seleccionamos los datos de la vista ZVLENGUAJES_PROG. SET PF-STATUS '100'. ENDFORM. OK_CODE = SY-UCOMM. " STATUS_0100 OUTPUT Establecemos el menú y título del programa. 393 . L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. " USER_COMMAND_0100 INPUT Asignamos acciones para el código de funciones. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. CREATE OBJECT G_ALV_TREE 394 .CASE OK_CODE. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 = LIFETIME_DYNPRO_DYNPRO_LINK = 5. ENDCASE. DATA: L_TREE_CONTAINER_NAME(30) TYPE C. LEAVE SCREEN. *&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. ENDMODULE. SET SCREEN 0. PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER. ENDFORM. = 1 = 2 = 3 = 4 = 6 = 7. = G_CUSTOM_CONTAINER = = '' = 'X' = '' CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE ILLEGAL_NODE_SELECTION_MODE = 5 PERFORM CREATE_HIERARCHY. CALL METHOD G_ALV_TREE->SET_TABLE_FOR_FIRST_DISPLAY EXPORTING IS_HIERARCHY_HEADER = L_HIERARCHY_HEADER CHANGING IT_OUTTAB IT_FIELDCATALOG = T_TREE[] = GT_FIELDCAT_TREE.EXPORTING PARENT NODE_SELECTION_MODE ITEM_SELECTION NO_HTML_HEADER NO_TOOLBAR EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR FAILED ILLEGAL_COLUMN_NAME PERFORM FILL_CATALOG_TREE. " INIT_TREE 395 . Llamámos al FORM BUILD_HIERARCHY_HEADER. Creamos el objeto G_ALV_TREE asignándolo a nuestro contenedor G_CUSTOM_CONTAINER.Creamos el contenedor G_CUSTOM_CONTAINER pasando como parámetro el nombre de nuestro CUSTOM_CONTROL contenido en la variable L_TREE_CONTAINER_NAME. Llamámos al método SET_TABLE_FOR_FIRST_DISPLAY para llamar al ALV. 396 . donde establecemos los detalles de la cabecera. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. donde creamos la estructura del ALV. Finalmemte llamámos al FORM CREATE_HIERARCHY. GS_FIELDCAT-OUTPUTLEN = 20. GS_FIELDCAT-COL_POS = 1. Llamámos al FORM FILL_CATALOG_TREE donde llenaremos el catálogo del ALV. Programa'. CLEAR GS_FIELDCAT. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. GS_FIELDCAT-SCRTEXT_S = 'Nom. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. *&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. "BUILD_HIERARCHY_HEADER La cabecera del ALV va a tener el título “Código”. *&----------------------------------------------------* * FORM build_hierarchy_header * *&----------------------------------------------------* FORM BUILD_HIERARCHY_HEADER CHANGING P_HIERARCHY_HEADER TYPE TREEV_HHDR.CLEAR GS_FIELDCAT. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-OUTPUTLEN = 15. ENDFORM. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. "fill_catalog_tree Creamos el catálogo del ALV. una longitud de 60. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. ENDFORM. GS_FIELDCAT-COL_POS = 2. *&----------------------------------------------------* *& Form create_hierarchy * 397 . CLEAR P_HIERARCHY_HEADER. P_HIERARCHY_HEADER-HEADING = 'Código'(300). P_HIERARCHY_HEADER-WIDTH = 60. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. CLEAR L_ROOT_KEY. CLEAR L_NEXT_KEY.*&----------------------------------------------------* FORM CREATE_HIERARCHY. ENDLOOP. HEADER = <FS_HEADER>-LENGUAJE. ENDFORM. ENDLOOP. LOOP AT T_HEADER ASSIGNING <FS_HEADER>. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. L_LAST_KEY TYPE LVC_NKEY. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. "CREATE_HIERARCHY 398 . PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY. W_MENGE_TEXT(13) TYPE C. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. HEADER TYPE STRING. CLEAR L_ROOT_KEY. DATA: L_ROOT_KEY TYPE LVC_NKEY. L_NEXT_KEY TYPE LVC_NKEY. Una vez que terminamos llamámos al método FRONTEND_UPDATE para refrescar los valores del ALV. asignamos el valor del campo LENGUAJE al campo HEADER (Esta variable dará un texto al NODO). Llamamos al FORM ADD_NODE para agregar un nuevo nodo. esto para poder agregarlos utilizando el FORM ADD_LEAF. CALL METHOD G_ALV_TREE->ADD_NODE 399 . = = L_NODE_TEXT = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME. Luego recorremos todos los registros de la tabla T_PROGRAMAS buscando los registros que tengan el campo LENGUAJE igual que el nodo.Recorremos los registros de la tabla T_HEADER. *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. LS_TREE TYPE TY_PROGRAMAS. L_NODE_TEXT = EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP I_NODE_TEXT IS_OUTTAB_LINE IMPORTING E_NEW_NODE_KEY = L_NEXT_KEY. DATA: L_NODE_TEXT TYPE LVC_VALUE. *&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. "ADD_NODE Llamámos al método ADD_NODE para crear un nuevo nodo. Grabamos.ENDFORM. = L_LAST_KEY. 400 . CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP IS_OUTTAB_LINE IMPORTING E_NEW_NODE_KEY ENDFORM. activamos y ejecutamos. "ADD_LEAF = = T_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD Llamámos al método ADD_NODE para crear un nuevo nodo. pasamos otro parámetro para que se cree como subnodo. Aunque claro. .. G_FAV_BEHAVIOUR TYPE REF TO CL_DRAGDROP. G_LINE_BEHAVIOUR TYPE REF TO CL_DRAGDROP. no es muy útil que digamos puesto que no hace.Así que vamos a agregar algunas cosas adicionales. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM.nada. * *=====================================================* 401 ..Agregar validaciones y eventos Si bien el programa funciona. L_HIERARCHY_HEADER TYPE TREEV_HHDR. G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE. L_LAST_KEY TYPE LVC_NKEY.... W_NODE_KEY TYPE LVC_NKEY. PUBLIC SECTION. CP_NODE_KEY TYPE LVC_NKEY. G_FAV_BEHAVIOUR objeto que determina que el folder puede aceptar un nuevo nodo. G_LINE_BEHAVIOUR objeto que determina que el nodo puede moverse. METHODS: 402 . CP_NODE_TEXT almacena el texto del nodo y CP_NODE_KEY almacena el índice del nodo. W_NODE_KEY variable para almacenar el nodo que se ha movido de carpeta. DATA: CPS_PROGRAMAS TYPE TY_PROGRAMAS. PUBLIC SECTION.Agregamos algunas variables. CPS_PROGRAMAS sirve como una cabecera con los datos de los nodos. *-----------------------------------------------------* * CLASS lcl_dnd_event_receiver DEFINITION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER DEFINITION. *-----------------------------------------------------* * CLASS LCL_DRAGDROPOBJ DEFINITION * *-----------------------------------------------------* CLASS LCL_DRAGDROPOBJ DEFINITION. ENDCLASS. L_LAST_KEY determina el nodo padre. CP_NODE_TEXT TYPE LVC_VALUE. "LCL_DRAGDROPOBJ DEFINITION Definimos algunas variables de clase. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ. CALL METHOD SENDER->GET_OUTTAB_LINE EXPORTING I_NODE_KEY IMPORTING E_OUTTAB_LINE = DATAOBJ->CPS_PROGRAMAS E_NODE_TEXT = DATAOBJ->CP_NODE_TEXT. METHOD HANDLE_LINE_DRAG. HANDLE_FAV_DROP FOR EVENT ON_DROP OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY DRAG_DROP_OBJECT. ENDCLASS. DATAOBJ->CP_NODE_KEY = NODE_KEY. CREATE OBJECT DATAOBJ. = NODE_KEY 403 .HANDLE_LINE_DRAG FOR EVENT ON_DRAG OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY FIELDNAME DRAG_DROP_OBJECT. *-----------------------------------------------------* * CLASS lcl_dnd_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER IMPLEMENTATION. "lcl_dnd_event_receiver DEFINITION Declaramos dos métodos para manejar el Drag & Drop (Arrastrar y soltar) en el ALV. DATAOBJ ?= DRAG_DROP_OBJECT->OBJECT. Con el método GET_OUTTAB_LINE llenamos las variables 404 . L_NEW_KEY TYPE LVC_NKEY. METHOD HANDLE_FAV_DROP. IF SY-SUBRC <> 0. CALL METHOD SENDER->FRONTEND_UPDATE. ENDMETHOD.DRAG_DROP_OBJECT->OBJECT = DATAOBJ. CATCH SYSTEM-EXCEPTIONS MOVE_CAST_ERROR = 1. ENDCLASS. W_NODE_KEY = DATAOBJ->CP_NODE_KEY. ENDIF. CALL METHOD DRAG_DROP_OBJECT->ABORT. ENDCATCH. "HANDLE_FAV_DROP "lcl_dnd_event_receiver IMPLEMENTATION "HANDLE_LINE_DRAG En el método HANDLE_LINE_DRAG. CALL METHOD G_ALV_TREE->DELETE_SUBTREE EXPORTING I_NODE_KEY = W_NODE_KEY. PERFORM ADD_LEAF USING DATAOBJ->CPS_PROGRAMAS NODE_KEY CHANGING DATAOBJ->CP_NODE_KEY. creamos un objeto DATAOBJ y le asignamos el contenido del nodo. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ. ENDMETHOD. DATA: LT_EVENTS TYPE CNTL_SIMPLE_EVENTS. 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.CPS_PROGRAMAS y CP_NODE_TEXT con los valores correspondientes al nodo. Asignamos el evento de Drag & Drop a una variable. Asignamos el valor del nodo que hemos movido a una variable auxiliar W_NODE_KEY. Llamamos al método FRONTEND_UPDATE para actualizar el ALV. Llamamos al FORM ADD_LEAF con el nodo que hemos movido de una carpeta a otra. PERFORM DEFINE_DND_BEHAVIOUR. Asignamos el nodo al evento de Drag & Drop. CALL METHOD G_ALV_TREE->SET_REGISTERED_EVENTS 405 . L_DND_EVENT_RECEIVER TYPE REF TO LCL_DND_EVENT_RECEIVER. 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. EXPORTING EVENTS EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR = 1 = 2 = LT_EVENTS ILLEGAL_EVENT_COMBINATION = 3. El FORM DEFINE_DND_BEHAVIOUR determina el tipo de Drag & Drop que se utilizará tanto para los nodos como para las carpetas. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. CREATE OBJECT L_DND_EVENT_RECEIVER. Handlers (Manejadores) para los eventos HANDLE_FAV_DROP y 406 . y ello. utilizamos los métodos y Además. Al final de INIT_TREE. establecemos los L_DND_EVENT_RECIEVER utilizar los eventos. agregamos este código. HANDLE_LINE_DRAG. nos sirven para registrar y GET_REGISTERED_EVENTS SET_REGISTERED_EVENTS. Para LCL_DND_EVENT_RECIEVER. Las tablas internas LT_EVENTS. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_LINE_DRAG FOR G_ALV_TREE. L_EVENT. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_FAV_DROP FOR G_ALV_TREE. L_HANDLE_FAVOURITE_FOLDER TYPE I. L_LAYOUT_NODE TYPE LVC_S_LAYN. DATA: L_NODE_TEXT TYPE LVC_VALUE. llamamos al método FRONTEND_UPDATE para actualizar el ALV. LS_TREE TYPE TY_PROGRAMAS. CALL METHOD G_ALV_TREE->ADD_NODE 407 . L_LAYOUT_NODE-ISFOLDER = 'X'. CALL METHOD G_FAV_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_FAVOURITE_FOLDER. L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_FAVOURITE_FOLDER. L_NODE_TEXT = EXPORTING I_RELAT_NODE_KEY = L_ROOT_KEY I_RELATIONSHIP I_NODE_TEXT IS_NODE_LAYOUT IS_OUTTAB_LINE IMPORTING E_NEW_NODE_KEY = L_NEXT_KEY. *&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. = = L_NODE_TEXT = L_LAYOUT_NODE = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME.Finalmente. 408 . CALL METHOD G_LINE_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_LINE. *&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. L_HANDLE_LINE TYPE I. además. "ADD_NODE Modificamos un poco el FORM ADD_NODE. Pasamos el valor de la hacia el variable campo L_HANDLE_FAVOURITE_FOLDER DRAGDROPID de la variable L_LAYOUT_NODE. asignamos el valor “X” al campo ISFOLDER de la misma variable. nos van a ayudar para establecer que los nodos son carpetas. Las variables L_LAYOUT y L_HANDLE_FAVOURITE_FOLDER. Debemos pasar el parámetro IS_NODE_LAYOUT al método ADD_NODE. DATA: L_LAYOUT_NODE TYPE LVC_S_LAYN. y que pueden aceptar un subnodo dentro de ellas.ENDFORM. Utilizamos el método GET_HANDLE para obtener el manejador que nos permita asignar un ID al nodo. CREATE OBJECT G_LINE_BEHAVIOUR. CALL METHOD G_LINE_BEHAVIOUR->ADD 409 . Utilizando el método GET_HANDLE asignamos un manejador a la variable L_LAYOUT_NODE-DRAGDROPID. Pasamos el parámetro IS_NODE_LAYOUT al método ADD_NODE. "ADD_LEAF = = L_TREE = L_LAYOUT_NODE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD Modificamos un poco el FORM ADD_LEAF. EFFECT = CL_DRAGDROP=>COPY. = L_LAST_KEY. *&----------------------------------------------------* *& Form DEFINE_DND_BEHAVIOUR **&---------------------------------------------------* FORM DEFINE_DND_BEHAVIOUR. 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. CALL METHOD G_ALV_TREE->ADD_NODE EXPORTING I_RELAT_NODE_KEY = L_NEXT_KEY I_RELATIONSHIP IS_OUTTAB_LINE IS_NODE_LAYOUT IMPORTING E_NEW_NODE_KEY ENDFORM.L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_LINE. DATA: EFFECT TYPE I. 410 . CALL METHOD G_FAV_BEHAVIOUR->ADD EXPORTING FLAVOR DRAGSRC EFFECT ENDFORM. EFFECT = CL_DRAGDROP=>COPY. Es decir. " DEFINE_DND_BEHAVIOUR "#EC NOTEXT DROPTARGET = 'X' Creamos dos objetos G_LINE_BEHAVIOUR y G_FAV_BEHAVIOUR. = 'X' = ' ' = EFFECT. "#EC NOTEXT DROPTARGET = ' ' CREATE OBJECT G_FAV_BEHAVIOUR. llamaremos al método ADD. Con cada uno de ellos. cual funciona como objeto y cual como contenedor.EXPORTING FLAVOR DRAGSRC EFFECT = 'X' = 'X' = EFFECT. determinando cual se puede arrastrar y en donde se puede soltar. 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 . ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS.Crear un ALV Object Model Así como el ABAP evolucionó para mejor. * *=====================================================* 412 . *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. PERFORM CARGAR_DATOS. T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS. END OF TY_PROGRAMAS. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. PERFORM LLAMAR_ALV. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS.NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. T_TABLE TYPE REF TO CL_SALV_TABLE. * *=====================================================* *=====================================================* * START-OF-SELECTION START-OF-SELECTION. T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. LR_COLUMN->SET_LONG_TEXT( 'Id' ). T_DSPSET->SET_LIST_HEADER( 'Programas' ). ENDTRY.ENDFORM. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE CHANGING T_TABLE CATCH CX_SALV_MSG . LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ). T_FUNCTIONS->SET_ALL( ABAP_TRUE ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). TRY. LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Programa' ). = T_TABLE 413 . = T_PROGRAMAS ). T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). " CARGAR_DATOS *&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS. LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO. * *=====================================================* Declaramos un TYPES con todos los campos de la vista ZVLENGUAJES_PROG. T_TABLE TYPE REF TO CL_SALV_TABLE. END OF TY_PROGRAMAS. ENDFORM. ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG. T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS. * *=====================================================* 414 .T_TABLE->DISPLAY( ). pero de todos modos vamos a revisarlo un poco. " LLAMAR_ALV Como se darán cuenta. T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. es un código bastante pequeño. NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. . SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. 415 .Bastante obvio no? *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. PERFORM CARGAR_DATOS. T_DSPSET nos sirve para las opciones de visualización.Declaramos varias tablas internas. T_PROGRAMAS que guardará los datos que obtengamos de la vista. T_FUNCTIONS sirve para asignar las funciones de la barra de menús del ALV. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM LLAMAR_ALV. LR_COLUMN nos permite tomar las características de una columna del ALV.. T_TABLE es un parámetro para el método FACTORY y sirve para crear la estructura del ALV. LV_SALV_COLUMNS_TABLE nos permite tomar todas las columnas de ALV. * *=====================================================* Tenemos dos FORM’s CARGAR_DATOS (Donde cargamos los datos) y LLAMAR_ALV (Donde llamamos al ALV). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). = T_PROGRAMAS ). LR_COLUMN->SET_LONG_TEXT( 'Programa' ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ).ENDFORM. T_FUNCTIONS->SET_ALL( ABAP_TRUE ). TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE CHANGING T_TABLE CATCH CX_SALV_MSG . LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). *&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. " CARGAR_DATOS Seleccionamos todos los campos de la vista ZVLENGUAJES_PROG. LR_COLUMN->SET_LONG_TEXT( 'Id' ). ENDTRY. T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). = T_TABLE 416 . T_TABLE que contendrá la estructura del ALV y T_PROGRAMAS. el ALV no puede determinar cual es el texto que le corresponde. T_TABLE->DISPLAY( ). Obtenemos todas las columnas del ALV. 417 . LR_COLUMN ?= LV_SALV_COLUMNS_TABLE>GET_COLUMN( 'ID_PROG' ). T_DSPSET->SET_LIST_HEADER( 'Programas' ). Establecemos que queremos utilizar todas las funciones. Continuando. por lo tanto. LR_COLUMN->SET_LONG_TEXT( 'Id' ). tanto ID_PROG como NOM_PROG no tienen asignado un elemento de datos. T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). pasando dos únicos parámetros. así que nos toca a nosotros asignarlo. que tiene los registros obtenidos de la vista. utilizamos T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). Obtenemos las características de la columna ID_PROG. Utilizando LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). Establecemos cual es texto de la columna. Para obtener las funciones standard del ALV T_FUNCTIONS->SET_ALL( ABAP_TRUE ). " LLAMAR_ALV Llamámos al método estático FACTORY de la clase CL_SALV_TABLE. Porque hacemos esto? Pues muy simple. ENDFORM.T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). .Obtenemos las características de salida. Vamos a redefinir a la clase LCL_HANDLE_EVENTS. T_TABLE->DISPLAY( ).nada. no es muy útil que digamos puesto que no hace... 418 .Así que vamos a agregar algunas cosas adicionales. Agregar validaciones y eventos Si bien el programa funciona. Asignamos un título al reporte.. T_DSPSET->SET_LIST_HEADER( 'Programas' ).. Llamamos y mostramos el ALV.. CLASS LCL_HANDLE_EVENTS DEFINITION DEFERRED. *-----------------------------------------------------* * CLASS lcl_handle_events DEFINITION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS DEFINITION. *-----------------------------------------------------* * CLASS lcl_handle_events IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS IMPLEMENTATION. PUBLIC SECTION. ENDCLASS. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. T_TABLE TYPE REF TO CL_SALV_TABLE. METHODS: ON_DOUBLE_CLICK FOR EVENT DOUBLE_CLICK OF CL_SALV_EVENTS_TABLE IMPORTING ROW COLUMN. ENDCLASS. METHOD ON_DOUBLE_CLICK. "lcl_handle_events DEFINITION Definimos un método llamado ON_DOUBLE_CLICK. PERFORM MOSTRAR_DETALLE USING ROW COLUMN. ENDMETHOD. "on_double_click "lcl_handle_events IMPLEMENTATION Implementamos el método llamado al FORM MOSTRAR_DETALLE. * *=====================================================* 419 . T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS. que lo que va a hacer es generar el evento del Doble Clic. Dentro de LLAMAR_ALV. * *=====================================================* Declaramos un Field-Symbol. GR_EVENTS TYPE REF TO LCL_HANDLE_EVENTS. El objeto GR_EVENTS nos permitirá registrar los eventos del ALV. LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE. agregamos el FORM PROCESS_EVENTS. 420 .T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. T_TABLE->DISPLAY( ). PERFORM PROCESS_EVENTS. " mostrar_detalle Si hemos hecho doble clic sobre un registro de la columna NOM_PROG. ENDFORM.*-----------------------------------------------------* *& Form mostrar_detalle * *-----------------------------------------------------* FORM MOSTRAR_DETALLE USING P_ROW P_COLUMN. 421 . CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-LENGUAJE <FS_PROGRAMAS>-ENTORNO INTO MENSAJE SEPARATED BY SPACE. entonces leemos el registro. IF P_COLUMN EQ 'NOM_PROG'. READ TABLE T_PROGRAMAS INDEX P_ROW ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. 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. ENDIF. DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. SET HANDLER GR_EVENTS->ON_DOUBLE_CLICK FOR LR_EVENTS. 422 . Este sería el resultado del reporte. Creamos el objeto GR_EVENTS y le asignamos el HANDLER ON_DOUBLE_CLICK. " process_events Utilizando el método estático GET_EVENT. ENDFORM. LR_EVENTS = T_TABLE->GET_EVENT( ). le decimos que reaccione ante el doble clic.*&----------------------------------------------------* *& Form process_events * *&----------------------------------------------------* FORM PROCESS_EVENTS. es decir. obtenemos el evento definido para nuestro ALV. DATA: LR_EVENTS TYPE REF TO CL_SALV_EVENTS_TABLE. CREATE OBJECT GR_EVENTS. 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. END OF TY_GRAPHIC_TABLE. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_GRAPHIC_TABLE. L_BYTECOUNT TYPE I. PICTURE TYPE REF TO CL_GUI_PICTURE. Este es el código. URL(255) TYPE C. GRAPHIC_SIZE TYPE I. * *=====================================================* * *=====================================================* * *=====================================================* 423 . CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE. pero ahora. LINE(255) TYPE X. L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0. creanmé que es muy útil. ENDCASE. " USER_COMMAND_0100 INPUT 424 . CLEAR SY-UCOMM. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. CALL SCREEN 0100. " STATUS_0100 OUTPUT * *=====================================================* *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. ENDMODULE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. ENDMODULE. OK_CODE = SY-UCOMM. SET PF-STATUS '100'.*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM LOAD_IMAGE. SET SCREEN 0. CASE OK_CODE. LEAVE SCREEN. SET TITLEBAR '100'. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV'. CALL FUNCTION 'SAPSCRIPT_GET_GRAPHIC_BDS' EXPORTING I_OBJECT I_NAME I_ID I_BTYPE IMPORTING E_BYTECOUNT TABLES CONTENT EXCEPTIONS NOT_FOUND = 1 BDS_GET_FAILED = 2 BDS_NO_CONTENT = 3 OTHERS = 4. PICTURE EXPORTING PARENT = CONTAINER1. = L_CONTENT = L_BYTECOUNT = 'GRAPHICS' = 'ENJOY' = 'BMAP' = 'BCOL' CALL FUNCTION 'SAPSCRIPT_CONVERT_BITMAP' EXPORTING OLD_FORMAT NEW_FORMAT IMPORTING BITMAP_FILE_BYTECOUNT = GRAPHIC_SIZE = 'BDS' = 'BMP' BITMAP_FILE_BYTECOUNT_IN = L_BYTECOUNT 425 .*&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE. CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_GRAPHIC_TABLE. = T_GRAPHIC_TABLE = 'IMAGE' SUBTYPE = 'BMP' = 1. Es un código sencillo y corto. así que será fácil entenderlo.TABLES BDS_BITMAP_FILE BITMAP_FILE EXCEPTIONS OTHERS CALL FUNCTION 'DP_CREATE_URL' EXPORTING TYPE TABLES DATA CHANGING URL = URL. ENDFORM. END OF TY_GRAPHIC_TABLE. = L_CONTENT = T_GRAPHIC_TABLE CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. * *=====================================================* 426 . LINE(255) TYPE X. " load_image Revisemos el código por partes. Esto es porque las imágenes de almacenan en formato hexadecimal. * *=====================================================* OK_CODE almacena el valor del código de función. * *=====================================================* Declaramos una tabla interna de tipo TY_GRAPHIC_TABLE. URL(255) TYPE C. GRAPHIC_SIZE TYPE I. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER. llamado LINE de 255 caracteres y de tipo X. L_BYTECOUNT TYPE I. 427 .Declaramos un TYPE llamado TY_GRAPHIC_TABLE que contiene un único campo. URL almacena una dirección donde se guarda la imagen en forma temporal. L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE. PICTURE TYPE REF TO CL_GUI_PICTURE. CALL SCREEN 0100. SET TITLEBAR '100'. PICTURE objeto que cargará y mostrará la imagen en el Dynpro. L_CONTENT almacena el contenido de la imagen. PERFORM LOAD_IMAGE. * *=====================================================* Llamamos al Dynpro 100 para mostrar la imagen. " STATUS_0100 OUTPUT 428 . L_BYTECOUNT cuenta el número de bytes de la imagen que queremos visualizar. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. ENDMODULE. SET PF-STATUS '100'. GRAPHIC_SIZE es el tamaño de la imagen luego de convetirla a BMP.CONTAINER1 contiene el nombre de nuestro CUSTOM_CONTROL. Llamamos a la barra de menús y al título del programa. *&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE. PICTURE EXPORTING PARENT = CONTAINER1. en el FORM LOAD_IMAGE vamos a cargar la imagen en el Dynpro. CALL FUNCTION 'SAPSCRIPT_GET_GRAPHIC_BDS' EXPORTING I_OBJECT I_NAME I_ID I_BTYPE IMPORTING E_BYTECOUNT TABLES CONTENT EXCEPTIONS NOT_FOUND = 1 BDS_GET_FAILED = 2 BDS_NO_CONTENT = 3 OTHERS = 4. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV'. = L_CONTENT = L_BYTECOUNT = 'GRAPHICS' = 'ENJOY' = 'BMAP' = 'BCOL' CALL FUNCTION 'SAPSCRIPT_CONVERT_BITMAP' EXPORTING OLD_FORMAT NEW_FORMAT = 'BDS' = 'BMP' 429 . Además. " load_image Creamos los objetos CONTAINER1 (Asociado a nuestro CUSTOM_CONTROL) y PICTURE (Mostrará la imagen en el contenedor). CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. 430 .BITMAP_FILE_BYTECOUNT_IN = L_BYTECOUNT IMPORTING BITMAP_FILE_BYTECOUNT TABLES BDS_BITMAP_FILE BITMAP_FILE EXCEPTIONS OTHERS CALL FUNCTION 'DP_CREATE_URL' EXPORTING TYPE TABLES DATA CHANGING URL = URL. ENDFORM. = L_CONTENT = T_GRAPHIC_TABLE = GRAPHIC_SIZE CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. = T_GRAPHIC_TABLE = 'IMAGE' SUBTYPE = 'BMP' = 1. Llamamos a la función DP_CREATE_URL para generar una dirección donde se encuentra almacenada temporalmente la imagen BMP. Llamamos a la función SAPSCRIPT_CONVERT_BITMAP para convertir la imagen a un Bitmap. Llamamos al método SET_DISPLAY_MODE para mostrar la imagen. 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. que en este caso es “ENJOY”. * *=====================================================* * *=====================================================* * *=====================================================* 432 . CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER... W_SUBRC TYPE SY-SUBRC. V_URL TYPE CHAR255. PARAMETERS: FILE LIKE RLGRAP-FILENAME. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. Este es el código. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_FILETAB TYPE FILETABLE. esto si que no creo que lo lleguen a necesitar alguna vez.Leer PDF’s Bueno. vale la pena conocerlo. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM.Pero bueno. MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER. CALL SCREEN 0100. 433 . CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. ENDIF.pdf' DEFAULT_FILENAME = '*. EXIT.SELECTION-SCREEN END OF BLOCK TEST. = 'Seleccionar archivo' = '*. FILE = <FS_FILETAB>. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. IF FILE IS INITIAL.pdf' * *=====================================================* READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CNTL_SYSTEM_ERROR = 2 = CONTAINER IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. ENDIF. CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT EXCEPTIONS CNTL_ERROR OTHERS = 1 = 3.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. IF CONTAINER IS INITIAL. SET PF-STATUS '100'. CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. SET TITLEBAR '100'. 434 . V_URL = FILE. CREATE OBJECT CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS CNTL_ERROR OTHERS = 1 = 2. CLEAR V_URL. ENDMODULE. LEAVE SCREEN. OK_CODE = SY-UCOMM. que no es más que una tabla con un campo de 1024 caracteres de longitud. * *=====================================================* Declaramos la tabla interna T_FILETAB de tipo FILETABLE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. ENDMODULE.ENDIF. SET SCREEN 0. CASE OK_CODE. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. CLEAR SY-UCOMM. ENDCASE. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_FILETAB TYPE FILETABLE. 435 . " USER_COMMAND_0100 INPUT Revisemos un poco el código. * *=====================================================* OK_CODE almacena el código de función. V_URL contiene la ruta donde se encuentra el ALV. W_SUBRC almacena el valor de retorno de llamar al método FILE_OPEN_DIALOG. * *=====================================================* Declaramos un Field-Symbol para la tabla T_FILETAB. W_SUBRC TYPE SY-SUBRC.*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. CONTAINER almacena el nombre de nuestro CUSTOM_CONTROL. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. MY_PDF_VIEWER es un objeto que nos permite visualizar un ALV. CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. V_URL TYPE CHAR255. MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER. 436 . Este parámetro. * *=====================================================* Llamamos a la pantalla 100 de nuestro Dynpro. recogerá la ruta donde se encuentra el PDF que queremos visualizar. CALL SCREEN 0100. SELECTION-SCREEN END OF BLOCK TEST. PARAMETERS: FILE LIKE RLGRAP-FILENAME. El evento AT-SELECION-SCREEN se ejecuta cuando llamamos al parámetro FILE. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. *&----------------------------------------------------* *& 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 = '*.pdf' 437 .*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. IF FILE IS INITIAL.FILE_FILTER CHANGING FILE_TABLE RC = '*. 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.pdf' = T_FILETAB = W_SUBRC. EXIT. SET TITLEBAR '100'. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. SET PF-STATUS '100'. ENDIF. Debemos leer la tabla interna T_FILETAB y asignar su contenido al parámetro FILE. FILE = <FS_FILETAB>. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. CLEAR V_URL. 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. ENDIF. creamos el objeto CONTAINER que hace referencia a nuesteo CUSTOM_CONTROL. ENDIF. CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT EXCEPTIONS CNTL_ERROR OTHERS = 1 = 3. ENDMODULE. CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. 439 . V_URL = FILE.CNTL_ERROR OTHERS = 1 = 2. " STATUS_0100 OUTPUT Además de asignar la barra de menús y el título al programa. CNTL_SYSTEM_ERROR = 2 = CONTAINER IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. * *=====================================================* 440 . *=====================================================* * DECLARACION DE TYPES TYPES: T_XLINE(2048) TYPE X. agregan un gusto especial a la programación en ABAP. Este es el código. pero que definitivamente.Comprimir (zip) archivos Este es otro de esos programas que no utilizaremos casi nunca. W_SIZE TYPE I. SIZE TYPE I. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. W_EXT(4) TYPE C. <FS_RESULT_TAB> LIKE LINE OF RESULT_TAB. OUTPUT_X TYPE XSTRING. *=====================================================* * DECLARACION DE VARIABLES DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. W_SUBRC TYPE SY-SUBRC. INPUT_X TYPE XSTRING. * *=====================================================* * *=====================================================* * *=====================================================* 441 . W_FILE_OUT TYPE STRING. PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME. RESULT_TAB TYPE MATCH_RESULT_TAB. T_FILETAB TYPE FILETABLE.*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE. W_FILE_IN TYPE STRING. W_LINE TYPE STRING. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE).FILE_OUT LIKE RLGRAP-FILENAME. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. = W_FILE_IN = 'BIN' * *=====================================================* 442 .<FS_RESULT_TAB>-LENGTH. <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH. DESCRIBE TABLE RESULT_TAB LINES W_SIZE. W_SIZE = W_SIZE . FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. SELECTION-SCREEN END OF BLOCK TEST. W_SIZE = STRLEN( W_FILE_IN ) – <FS_RESULT_TAB>-OFFSET. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X. = INPUT_X IF CL_ZIP IS INITIAL. CREATE OBJECT CL_ZIP.CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER TABLES BINARY_TAB = DATA_TAB. CALL METHOD CL_ZIP->SAVE RECEIVING ZIP = OUTPUT_X. REFRESH DATA_TAB. CALL FUNCTION 'SCMS_XSTRING_TO_BINARY' EXPORTING BUFFER IMPORTING OUTPUT_LENGTH = SIZE TABLES BINARY_TAB = DATA_TAB. = OUTPUT_X 443 . ENDIF. FILE_IN = <FS_FILETAB>. = 'Seleccionar archivo' = '*. = W_FILE_OUT = 'BIN' *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN.*' DEFAULT_FILENAME = '*.*' READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>.CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME FILETYPE CHANGING DATA_TAB = DATA_TAB. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. CLEAR T_FILETAB. EXIT. IF FILE_IN IS INITIAL. 444 . ENDIF. W_FILE_IN = FILE_IN. 445 . pero algunas cosas que pueden confundir un poco a simple vista. W_EXT = W_FILE_OUT+W_SIZE(4). IF W_EXT NE '. ELSE.REFRESH T_FILETAB. = 'Seleccionar archivo' = '*. ENDIF. AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_OUT. Revisemos un poco el código. W_SIZE = STRLEN( W_FILE_OUT ). CONCATENATE W_FILE_OUT '.4. W_SIZE = W_SIZE . EXIT. FILE_OUT = <FS_FILETAB>. IF FILE_OUT IS INITIAL. Nos es complicado. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. FILE_OUT = W_FILE_OUT. ENDIF. W_FILE_OUT = FILE_OUT.zip'.zip' INTO W_FILE_OUT.zip' READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>.zip' DEFAULT_FILENAME = '*. RESULT_TAB TYPE MATCH_RESULT_TAB.*=====================================================* * DECLARACION DE TYPES TYPES: T_XLINE(2048) TYPE X. SIZE TYPE I. * *=====================================================* Declaramos un TYPE llamado T_XLINE de 2048 caracteres de tipo X. OUTPUT_X TYPE XSTRING. que nos sirve para guardar las rutas de los archivos y finalmente RESULT_TAB de tipo MATCH_RESULT_TAB. otra tabla llamada T_FILETAB que hace referencia a FILETABLE. * *=====================================================* 446 . *=====================================================* * DECLARACION DE VARIABLES DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP. T_FILETAB TYPE FILETABLE. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE. INPUT_X TYPE XSTRING. que nos sirve para almacenar las ocurrencias de una búsqueda de texto. * *=====================================================* Declaramos una tabla interna llamada DATA_TAB que hace referencia al TYPE T_XLINE. es decir Hexadecimal. CL_ZIP es un objeto que nos permitirá comprimir el documento de entrada. W_SIZE almacena el tamaño en líneas de la tabla interna RESULT_TAB. *=====================================================* * DECLARACION DE FIELD-SYMBOLS * *=====================================================* 447 . SIZE determina el tamaño del archivo que está siendo subido al servidor. W_FILE_OUT almacena la ruta del archivo de salida. W_EXT(4) TYPE C. W_FILE_IN almacena la ruta del archivo de entrada. W_SUBRC almacena el resultado de ejecutar la acción de subir los archivos. W_FILE_OUT TYPE STRING. W_LINE almacena el nombre final que tendrá el archivo de salida. INPUT_X guarda el contenido de convertir el archivo de Binario a Hexadecimal (Archivo de entrada).W_SUBRC TYPE SY-SUBRC. W_SIZE TYPE I. W_EXT almacena la extensión del archivo de salida. W_FILE_IN TYPE STRING. W_LINE TYPE STRING. OUTPUT_X guarda el contenido de convertir el archivo de Hexadecimal a Binario (Archivo de salida). FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. Declaramos dos parámetros. uno de entrada y otro de salida. PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME.FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. FILE_OUT LIKE RLGRAP-FILENAME. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. DESCRIBE TABLE RESULT_TAB LINES W_SIZE. Declaramos dos Field-Symbols. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. <FS_RESULT_TAB> LIKE LINE OF RESULT_TAB. READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. SELECTION-SCREEN END OF BLOCK TEST. uno para FILETAB y otro para RESULT_TAB. * *=====================================================* 448 . <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH.W_SIZE = STRLEN( W_FILE_IN ) – <FS_RESULT_TAB>-OFFSET. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X. = W_FILE_IN = 'BIN' CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER TABLES BINARY_TAB = DATA_TAB. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE). = INPUT_X IF CL_ZIP IS INITIAL. CREATE OBJECT CL_ZIP. W_SIZE = W_SIZE . CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB. 449 . ENDIF.<FS_RESULT_TAB>-LENGTH. = OUTPUT_X CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME FILETYPE CHANGING DATA_TAB = DATA_TAB. 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 IMPORTING OUTPUT_LENGTH = SIZE TABLES BINARY_TAB = DATA_TAB. = W_FILE_OUT = 'BIN' 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. 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. 450 . Finalmente. la longitud del símbolo “\”). Restamos a W_SIZE el valor del campo LENGTH. Con el módulo de funciones SCMS_BINARY_TO_XSTRING convertimos el contenido del archivo de Binario a Hexadecimal.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). 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 GUI_UPLOAD para subir el contenido del archivo de entrada. 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. Reemplazamos el valor del OFFSET. llamamos al método SAVE para crear el archivo ZIP con el archivo de entrada. Creamos el objeto CL_ZIP y llamamos al método ADD para agregar el archivo de entrada al nuevo ZIP. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' 451 . = '*. REFRESH T_FILETAB.DEFAULT_FILENAME = '*. FILE_IN = <FS_FILETAB>. IF FILE_IN IS INITIAL.*' FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. Llamamos al método FILE_OPEN_DIALOG para poder almacenar la ruta del archivo de entrada.*' READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. 452 . EXIT. CLEAR T_FILETAB. ENDIF. W_FILE_IN = FILE_IN. yo lo he utilizado para proyectos personales y no de trabajo. TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. Este es el código. * *=====================================================* * *=====================================================* * *=====================================================* 453 . CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. CALL SCREEN 0100. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM.Crear un Control de Texto Este programa es bastante útil y necesario aunque que quizás no lo utilicen mucho. En lo personal. *=====================================================* * DECLARACION DE CONSTANTES CONSTANTS: LINE_LENGTH TYPE I VALUE 254. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. " STATUS_0100 OUTPUT *&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. CLEAR SY-UCOMM. CASE OK_CODE.*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. ENDMODULE. SET TITLEBAR '100'. OK_CODE = SY-UCOMM. " USER_COMMAND_0100 INPUT 454 . ENDCASE. LEAVE SCREEN. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. ENDMODULE. PERFORM CALL_EDITOR. SET PF-STATUS '100'. SET SCREEN 0. *&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR . IF TEXT_EDITOR IS INITIAL. CREATE OBJECT TEXT_EDITOR EXPORTING WORDWRAP_MODE WORDWRAP_POSITION CL_GUI_TEXTEDIT=>TRUE PARENT EXCEPTIONS ERROR_CNTL_CREATE ERROR_CNTL_INIT ERROR_CNTL_LINK ERROR_DP_CREATE GUI_TYPE_NOT_SUPPORTED OTHERS ENDIF. = 1 = 2 = 3 = 4 = 5 = 6. = CUSTOM_CONTAINER = = LINE_LENGTH CL_GUI_TEXTEDIT=>WORDWRAP_AT_FIXED_POSITION WORDWRAP_TO_LINEBREAK_MODE = 455 . CREATE OBJECT CUSTOM_CONTAINER EXPORTING CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 = 'CUSTOM_ALV' LIFETIME_DYNPRO_DYNPRO_LINK = 5. ENDFORM. * *=====================================================* La variable OK_CODE almacena el código de función. " CALL_EDITOR Revisemos el código paso a paso. CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER. TEXT_EDITOR hace referencia al objeto que crea el control de texto. CUSTOM_CONTAINER es un objeto que creará el contenedor para nuestro control de texto.CALL METHOD CL_GUI_CFW=>FLUSH. *=====================================================* * DECLARACION DE CONSTANTES CONSTANTS: LINE_LENGTH TYPE I VALUE 254. 456 . *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM. Esto determina cada cuantos caracteres debería hacer un salto de línea automático. * *=====================================================* Declaramos una constante llamada LINE_LENGTH de tipo I con el valor 254. TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. SET TITLEBAR '100'. * *=====================================================* Llamamos a la pantalla 100 del Dynpro. " STATUS_0100 OUTPUT Asignamos el menú y el título del programa. Llamamos al FORM CALL_EDITOR. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. CREATE OBJECT CUSTOM_CONTAINER 457 . ENDMODULE. PERFORM CALL_EDITOR. En donde llamamos al control de texto. SET PF-STATUS '100'. IF TEXT_EDITOR IS INITIAL. CALL SCREEN 0100.*=====================================================* * START-OF-SELECTION START-OF-SELECTION. *&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR . ENDFORM. CALL METHOD CL_GUI_CFW=>FLUSH. = CUSTOM_CONTAINER = = LINE_LENGTH CL_GUI_TEXTEDIT=>WORDWRAP_AT_FIXED_POSITION WORDWRAP_TO_LINEBREAK_MODE = Creamos el contenedor para el control de texto CUSTOM_CONTAINER. " CALL_EDITOR = 1 = 2 = 3 = 4 = 5 = 6.EXPORTING CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 = 'CUSTOM_ALV' LIFETIME_DYNPRO_DYNPRO_LINK = 5. CREATE OBJECT TEXT_EDITOR EXPORTING WORDWRAP_MODE WORDWRAP_POSITION CL_GUI_TEXTEDIT=>TRUE PARENT EXCEPTIONS ERROR_CNTL_CREATE ERROR_CNTL_INIT ERROR_CNTL_LINK ERROR_DP_CREATE GUI_TYPE_NOT_SUPPORTED OTHERS ENDIF. Creamos el objeto TEXT_EDITOR. 458 . Como podemos ver. contamos con dos botones Load Local File (Cargar archivo local) archivo local) y Save as Local File (Grabar como .Limpiamos los controles con el método FLUSH. 459 . modificarlo y guardarlo. Lo cual significa que podemos cargar cualquier archivo. 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 (Crear Nodo) Node 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 contenedor). Create Container Form (Crear formulario En la ventana que aparece a continuación, debemos presionar el botón Context contenedor. para poder asignar un valor a nuestro 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 . solamente debemos grabar y activar. Asignamos un nombre y una descripción y aceptamos. En la siguiente pantalla. Una vez que todo se ha activado. debemos crear una WebDynpro Application (Aplicación WebDynpro).Seleccionamos todos y aceptamos. 472 . Presionamos el botón Test/Execute (Probar/Ejecutar) presionamos F8. presionamos el botón Log On . 473 . o El navegador nos muestra una pantalla de login. así que debemos logearnos. Para esto. Como podemos ver. no va a pasar nada. por lo cual por mucho que presionemos F4. En este caso. el campo ID_PROG no tiene una ayúda de búsqueda asociada. Cerremos el browser y retornemos a nuestro programa. nuestro parámetro de entrada aparece perfectamente en el browser de internet. 474 . pestaña Layout.Regresamos a la vista ZDUMMY_VIEW. 475 . Le asignamos un título y hacemos clic derecho sobre el nodo TABLE para seleccionar Create Binding (Crear Atadura). Elegimos el componente Table (Tabla) de la pestaña Standard Complex (Complejos Estándar). Escogemos el Context ZLENG_NODE y dejamos todos los registro seleccionados y continuamos. Asignamos textos a las cabeceras y tendremos algo como esto. 476 . el cual tendrá el texto “Mostrar!”. 477 .Regresamos a la pestaña Standard Simple y seleccionamos el control Button (Botón). 478 .Debemos asignar una acción al botón. Nos vamos a la pestaña Actions (Acciones) y veremos nuestra acción. Asignamos el nombre SHOW y una descripción breve. por lo cual presionamos el botón OnAction. WD_CONTEXT->GET_ATTRIBUTE( exporting NAME = 'ID_PROG' importing VALUE = ID_PROG ). ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE.Debemos presionar el botón ABAP Routine (Rutina ABAP) para poder asignar el código a nuestra acción. NODE_LENG = 479 . METHOD ONACTIONSHOW. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG EQ ID_PROG. DATA: ID_PROG TYPE STRING. WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). NODE_LENG->BIND_TABLE( ITAB_LENG ). ITAB_LENG es una tabla interna que hace referencia a la vista ZVLENGUAJES_PROG. Obtenemos el valor de atributo ID_PROG. NODE_LENG->BIND_TABLE( ITAB_LENG ). esta es una interface que controla los nodos asociados a nuestro programa. WD_CONTEXT->GET_ATTRIBUTE( exporting NAME = 'ID_PROG' importing VALUE = ID_PROG ). Declaramos la variable NODE_LENG que hace referencia a IF_WD_CONTEXT_NODE. ID_PROG es una variable de tipo String. Seleccionamos el registro de la vista ZVLENGUAJES_PROG siempre y cuando cumpla con el parámetro ID_PROG. 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' ). es decir. de nuestro parámetro de entrada. ENDMETHOD. 480 . ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. 481 . NODE_LENG->BIND_TABLE( ITAB_LENG ). es que agregamos una línea de cabecera a nuestra tabla interna. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). Lo más resaltante de este código. APPEND INITIAL LINE TO ITAB_LENG. para que el Table Control tenga algo que mostrar cuando lanzemos el programa. 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. endmethod. method WDDOINIT. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE.Hay algo más que debemos hacer y que es muy importante. Todo se ve muy bien. 482 .. pero estamos limitados a buscar solamente un valor..Así que vamos a agregar otra caja de texto para poder crear un rango de búsqueda. Renombramos el atributo ID_PROG a ID_PROG_INI. creamos un nuevo nodo. llamado PARAMETROS que no contendrá referencia a ningún tabla. Ahora. Solamente nos servirá como contenedor para los atributos. El nuevo atributo se llamará ID_PROG_FIN. puesto que ahora vamos a tener dos atributos distintos. 483 .Regresamos a la pestaña Context. Lo que hacemos es arrastrar los atributos a nuestro nodo PARAMETROS. 484 . Nuestro diseño quedará como se muestra a continuación. Creamos un nuevo Container Form. con dos parámetros de entrada. que nos servirán para definir nuestro rango.Regresamos al Layout y eliminamos el campo de texto ID_PROG. 485 . ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. ID_PROG_FIN TYPE STRING. FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG. DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. METHOD ONACTIONSHOW. DATA: ID_PROG_INI TYPE STRING. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'PARAMETROS' ).Regresamos a la pestaña Actions y al código del método Show. 486 . NODE_LENG->BIND_TABLE( ITAB_LENG ). <FS_IDPROG>-OPTION = 'BT'. 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. 487 .WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). <FS_IDPROG>-LOW = ID_PROG_INI. APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). DATA: ID_PROG_INI TYPE STRING. ENDMETHOD. WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ). <FS_IDPROG>-SIGN = 'I'. <FS_IDPROG>-HIGH = ID_PROG_FIN. ID_PROG_FIN TYPE STRING. con lo cual podremos definir un rango de valores para seleccionar de la vista. Declaramos dos variables. Asignamos el nodo PARAMETROS a nuestra variable NODE_LENG. NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). ID_PROG_INI e ID_PROG_FIN.DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. 488 . NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ). Declaramos la variable ID_PROG de tipo RANGE (Rango). APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. <FS_IDPROG>-SIGN = 'I'. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'PARAMETROS' ). Recuperamos los valores de ambos parámetros. FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG. Declaramos un Field-Symbol. <FS_IDPROG>-OPTION = 'BT'. cada cual almacenará el valor de su parámetro correspondiente. OPTION es el tipo de correspondencia entre los datos. Between Equal (Igual). 489 . LOW es el valor inicial y HIGH es En el select. con lo cual podemos utilizar el rango para pasar más de un valor como parámetro. donde BT (Entre) y EQ el valor final. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG IN ID_PROG. reemplazamos el EQ por un IN. y asignamos los valores correspondientes. Agregamos una línea de cabecera a nuestro rango. <FS_IDPROG>-HIGH = ID_PROG_FIN.<FS_IDPROG>-LOW = ID_PROG_INI. SIGN es el tipo de valor. 490 . JSP o PHP. una especio de ASP. viene a ser un lenguaje script basado en ABAP. se hace con BSP.BSP Introducción El BSP (Business Server Pages – Página del Servidor de Aplicaciones). Creando nuestro primer BSP Al igual que en el caso del WebDynpro. aunque esto no quiere decir que sea obsoleto o menos completo. El BSP es anterior al WebDynpro. 491 . así que nuevamente debemos ir a la transacción SE80 y escoger BSP Application (Aplicación BSP) en el menú. por el contrario. el BSP no tiene una transacción propia (Otra queja más para SAP). lo que no se puede hacer con WebDynpro. es decir. 492 . Creamos una página llamada index.bsp haciendo clic derecho Create Page (Crear Página).Creamos nuestra aplicación ZDUMMY_BSP. Creamos una nueva página. navigation->set_parameter( ‘ID_PROG’ ) nuestra página. nos es más que HTML con un par de características adicionales. onInputProcessing(show) nuestro FORM. En este caso. <%@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.En la pestaña Layout (Disposición) colocamos el siguiente código. show representa a 493 . Indica que estamos estableciendo el campo ID_PROG como un parámetro de salida de Evento llamado cuando se ejecuta una acción de procesamiento de datos. w_id_prog = request->get_form_field( 'ID_PROG' ). select ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG EQ W_ID_PROG.Este es el código de la página. %> 494 . t_leng type standard table of ZVLENGUAJES_PROG. <%@page language="abap"%> <html> <body> <% data: w_id_prog type zvlenguajes_prog-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>. field-symbols: <fs_leng> like line of t_leng. en esta página hemos incluido código ABAP.<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. Esto es porque el BSP es un lenguaje script y se integra perfectamente con el HTML. estas dos páginas no se comunican entre sí. seleccionamos datos y los mostramos en una tabla. %> </table> </body> </html> Como podemos ver.bsp nos vamos a la pestaña Event Handler (Manejador de Eventos) y escogemos del menú OnInputProcessing.bsp. 495 . Además hemos llamado variables utilizando los tags <%= y %>. dentro de los tags <% y %>. Simplemente recibimos un parámetro de la página index. Hasta ahora. así que vamos a agregar algo de código para conectarlas. En la página index. Nos vamos a la aplicación con un doble clic. Si llamamos a nuestro FORM de la página index.Agregamos el siguiente código. CASE EVENT_ID. WHEN 'show'. 496 . NAVIGATION->SET_PARAMETER('ID_PROG'). EVENT_ID es una variable que almacena los “códigos de función” de las páginas.bsp. ENDCASE. NAVIGATION->NEXT_PAGE('SHOW_DATA'). 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). Debemos ingresar nuestro Usuario y Password para poder iniciar el 497 . establecemos la página principal en la pestaña Properties (Propiedades). Grabamos. presionando el botón Test (Probar) servidor. o presionando F8.Establecemos que index.bsp Finalmente.bsp llama al alias SHOW_DATA que representa a la página Show_Data. activamos y ejecutamos. 498 . bsp y modificamos ligeramente el código.Al ser HTML. Vamos a la pestaña Event Handler y al evento OnInputProcessing. podemos hacer lo que queramos con el formato de salida de la tabla. 499 . pero lo que vamos a hacer. es crear un rango de valores para poder hacer una mejor selección en el programa. al igual que con el WebDynpro. <%@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. dos parámetros ID_PROG_INI y ID_PROG_FIN. Regresamos a la página index. t_leng type standard table of ZVLENGUAJES_PROG. NAVIGATION->NEXT_PAGE('SHOW_DATA'). WHEN 'show'. <fs_r_leng>-SIGN = 'I'. <fs_r_leng> like line of r_leng.CASE EVENT_ID. <fs_r_leng>-LOW = W_ID_PROG_INI. w_id_prog_ini = request->get_form_field( 'ID_PROG_INI' ). r_leng type range of ZVLENGUAJES_PROG-ID_PROG.bsp En la pagína Show_Data. NAVIGATION->SET_PARAMETER('ID_PROG_INI'). <fs_r_leng>-HIGH = W_ID_PROG_FIN. w_id_prog_fin type zvlenguajes_prog-id_prog. ENDCASE. field-symbols: <fs_leng> like line of t_leng. <%@page language="abap" %> <html> <body> <% data: w_id_prog_ini type zvlenguajes_prog-id_prog. <fs_r_leng>-OPTION = 'BT'.bsp hacemos un pequeños cambios. 500 . Enviamos ambos parámetros a la página Show_Data. append initial line to r_leng assigning <fs_r_leng>. w_id_prog_fin = request->get_form_field( 'ID_PROG_FIN' ). NAVIGATION->SET_PARAMETER('ID_PROG_FIN'). select ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG in 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. 501 . %> <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>. asignamos los parámetros de entrada W_ID_PROG_INI y W_ID_PROG_FIN al rango y lo utilizamos para nuestro select. un field-Symbol <FS_R_LENG>. %> </table> </body> </html> Creamos un rango R_LENG. 502 . * *=====================================================* * *=====================================================* *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. T_FILETAB TYPE FILETABLE. Como era de esperarse. END OF TY_TAB. T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. LINE(100) TYPE C. * *=====================================================* 503 .ABAP y XML El XML (Extensible Markup Language – Lenguaje extensible de marcas) es un formato de intercambio de archivos muy utilizado en al actualidad. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB. puesto que es sumamente flexible. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. el ABAP nos permite trabajar con archivos XML de una manera bastante simple. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. W_FILE TYPE STRING. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. SELECTION-SCREEN END OF BLOCK TEST. SIZE TYPE I. PARAMETERS: FILE LIKE RLGRAP-FILENAME.*=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING. PERFORM DESCARGAR_XML. W_SUBRC TYPE SY-SUBRC. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM GENERAR_XML.xml' * *=====================================================* * *=====================================================* 504 . PERFORM OBTENER_DATOS. FILE_FILTER CHANGING FILE_TABLE RC = '*. EXIT. FILE = <FS_FILETAB>. " OBTENER_DATOS *&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. W_FILE = FILE. ENDFORM. IF FILE IS INITIAL. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. *&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. ENDIF.xml' = T_FILETAB = W_SUBRC. READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. CALL TRANSFORMATION ('ID') 505 . ELSE. " GENERAR_XML *&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. " DESCARGAR_XML = W_FILE = 'BIN' Revisemos el código fuente. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME FILETYPE CHANGING DATA_TAB ENDFORM. 506 . CALL FUNCTION 'SWA_STRING_TO_TABLE' EXPORTING CHARACTER_STRING = XML_OUT IMPORTING CHARACTER_TABLE = T_TAB. = T_TAB. ENDFORM.SOURCE TAB = T_ZLENG[] RESULT XML XML_OUT. * *=====================================================* Declaramos un TYPE que contiene un solo campo llamado LINE de 100 de longitud y tipo C. T_FILETAB TYPE FILETABLE. * *=====================================================* Declaramos un field-symbol. 507 . LINE(100) TYPE C. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. otra para guardar los datos de la Base de Datos y el último para guardar la ruta del archivo de salida. END OF TY_TAB. * *=====================================================* Creamos algunas tablas internas.*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB. una para guardar el XML. T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. W_FILE TYPE STRING. PERFORM OBTENER_DATOS. PERFORM DESCARGAR_XML. * *=====================================================* XML_OUT es una cadena que contendrá la información para generar el XML. * *=====================================================* 508 . *=====================================================* * START-OF-SELECTION START-OF-SELECTION. SELECTION-SCREEN END OF BLOCK TEST. PARAMETERS: FILE LIKE RLGRAP-FILENAME. Declaramos un parámetro de entrada para poder obtener la ruta donde se generará el archivo XML.*=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING. PERFORM GENERAR_XML. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. W_SUBRC TYPE SY-SUBRC. SIZE TYPE I. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC.xml' DEFAULT_FILENAME = '*. W_FILE = FILE. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. EXIT. FILE = <FS_FILETAB>. DESCARGAR_XML guarda el archivo en la ruta especificada. ELSE. = 'Seleccionar archivo' = '*. Obtenemos la ruta del archivo a descargar.OBTENER_DATOS nos sirve para seleccionar los datos de la vista. 509 . ENDIF. IF FILE IS INITIAL. GENERAR_XML crea el archivo XML.xml' READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. " 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. 510 . ENDFORM. *&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. ENDFORM. CALL TRANSFORMATION ('ID') SOURCE TAB = T_ZLENG[] RESULT XML XML_OUT.*&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. " OBTENER_DATOS Seleccionamos los registros de la vista. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. 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 FILETYPE CHANGING DATA_TAB ENDFORM. = T_TAB.*&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. El método GUI_DOWNLOAD nos permite descargar el archivo XML. 511 . " DESCARGAR_XML = W_FILE = 'BIN' SWA_STRING_TO_TABLE nos sirve para convertir la cadena XML_OUT a una tabla con los datos del XML. * *=====================================================* 512 . El código es practicamente el mismo. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB. LINE(100) TYPE C.Ahora que ya vimos como podemos generar un archivo XML a partir de una tabla interna. veamos como hacer lo contrario. es decir. END OF TY_TAB. generemos una tabla interna en base a un archivo XML. solo cambia el orden. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. W_FILE TYPE STRING. SELECTION-SCREEN END OF BLOCK TEST. T_FILETAB TYPE FILETABLE. * *=====================================================* * *=====================================================* * *=====================================================* 513 . W_SUBRC TYPE SY-SUBRC. T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. *=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING. <FS_ZLENG> LIKE LINE OF T_ZLENG.*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. SIZE TYPE I. 514 . *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE.xml' * *=====================================================* READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. ELSE. ENDIF. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. PERFORM IMPRIMIR. PERFORM CARGAR_XML. PERFORM GENERAR_TABLA_INTERNA. = 'Seleccionar archivo' = '*.xml' DEFAULT_FILENAME = '*. IF FILE IS INITIAL. EXIT.*=====================================================* * START-OF-SELECTION START-OF-SELECTION. W_FILE = FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE CHANGING DATA_TAB = T_TAB. " GENERAR_TABLA_INTERNA *&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[]. ENDFORM.*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. = W_FILE = 'BIN' CALL FUNCTION 'SWA_STRING_FROM_TABLE' EXPORTING CHARACTER_TABLE IMPORTING CHARACTER_STRING = XML_OUT. " CARGAR_XML = T_TAB 515 . ENDFORM. <FS_ZLENG>-LENGUAJE. LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. 516 . lo transforma en una cadena XML. ENDLOOP. (Con formato XML claro está). WRITE:/ <FS_ZLENG>-ID_PROG. ENDFORM. " IMPRIMIR Revisemos el código. Luego. PERFORM GENERAR_TABLA_INTERNA. PERFORM IMPRIMIR. <FS_ZLENG>-NOM_PROG. PERFORM CARGAR_XML. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. GENERAR_TABLA_INTERNA transforma la cadena XML en una tabla interna. IMPRIMIR muestra el resultado en pantalla. pero solamente las partes que han cambiado.*&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. <FS_ZLENG>-ENTORNO. * *=====================================================* CARGAR_XML carga el archivo y lo guarda en un tabla interna. CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE CHANGING DATA_TAB = T_TAB. = W_FILE = 'BIN' CALL FUNCTION 'SWA_STRING_FROM_TABLE' EXPORTING CHARACTER_TABLE IMPORTING CHARACTER_STRING = XML_OUT. 517 . " CARGAR_XML = T_TAB Utilizamos el método GUI_UPLOAD para cargar el archivo XML. Con el módulo de funciones SWA_STRING_FROM_TABLE convertimos la tabla interna en una cadena XML.*&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. ENDFORM. es bastante sencillo trabajar con XML y ABAP.*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. <FS_ZLENG>-ENTORNO. 518 . LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. WRITE:/ <FS_ZLENG>-ID_PROG. ENDFORM. ENDFORM. CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[]. " GENERAR_TABLA_INTERNA Utilizamos el CALL TRANSFORMATION para recibir una cadena XML y retornar una tabla interna. <FS_ZLENG>-NOM_PROG. *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. ENDLOOP. " IMPRIMIR Imprimimos el contenido de la tabla interna. Como pueden ver. <FS_ZLENG>-LENGUAJE. 519 . esta herramienta es indispensable para el trabajo con lenguajes script.sap. Perl y Python.sdn. ingresar a http://sdn. Ruby. De muy sencilla instalación. Rails. debemos ingresar a la siguiente dirección (Debemos ser usuarios del SDN – SAP Developer Network). el Scripting in a Box simplementese descarga y se configura. puesto que no existe una instalación. cuenta además con varios ejemplos (Incluyendo mi emulador de SE16 en PHP). reune a todos los lenguajes script que pueden conectados con NetWeaver.Scripting in a Box Scripting in a Box es una herramienta creada por Craig Cmehil de SAP AG.com Tools for Developers Downloads More Downloadable Scripting in a Box. al igual que el Eclipse. 520 .com/irj/sdn/go/portal/prtroot/docs/library/uuid/e5 0bd86e-0a01-0010-53bd-857585234a6a O. Esta herramienta basada en Eclipse. Como era de suponerse. Veamos algunas imagenes de Scripting a in Box. https://www. Para descargarlo. La instalación es lo mejor de todo.sap. lo cual lo hace excelente para aquellas personas que nunca han hecho una integración con NetWeaver. como PHP. 521 . 522 . debemos ingresar a la siguiente dirección. Dynpros. Esta herramienta. 523 . Podemos descargarla. http://code.google. puesto que SAPLink nos brinda una interfaz muy sencilla. Si bien existen muchas herramientas para descargar y cargar elementos de NetWeaver (Yo he creado varias de ellas). Creando paquetes basados en código XML.SAPLink SAPLink es una herramienta creada por Daniel McWeeney y Ed Herrmann de Colgate . deberemos ingresar a la dirección. WebDynpros. opción de descargar Plug-Ins y un constante monitoreo de los posibles errores. SmartForms y un largo etcétera.google. podemos almacenar Programas.com/p/saplink/ Y para los Plug-Ins.com/p/saplink/wiki/pluginList Veamos algunas cuantas imágenes. nos permite crear una verdadera librería de códigos para poder transportar o compartir con los demás.Palmolive. desarrollada en ABAP. no hay hasta el momento ninguna que pueda competir con SAPLink. http://code. 524 . 525 . 526 . BAPI’s.net/ Apache WebServer versión 2. pero accediendo a través de una interface web. ya depende de cada uno que tecnología utilizar. por lo cual.0.4-5. etc.apache.0. en vez de utilizar WebDynpro o BSP.org http://saprfc. Su sintaxis es bastante similar a la de C++. ejecutar funciones.2 SAPRFC 1. se conecten con NetWeaver.php. que nos permite que las páginas web que desarrollemos en PHP. 527 http://www. es un lenguaje orientado a objetos. 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.1. Es decir.Integración PHP-NetWeaver Introducción El PHP (PHP Preprocessor). es open source y en su versión 5 en adelante. Lleva varios años en el mercado. para obtener datos de tablas.sourceforge. conociendo C++ o Java. existe un conector llamado SAPRFC. hacer lo mismo que hacemos todos los días. En todo caso. es un lenguaje de programación para páginas web dinámicas. Si se preguntan porque utilizar PHP con NetWeaver.4 MiniWas.net http://httpd. la respuesta es muy simple: “PHP es gratuito. fácil de aprender y configurar”.55 NetWeaver Sneak Preview o SAP NetWeaver o MiniSAP o . es muy fácil de aprender. Gracias a Eduard Koucky. dentro de la carpeta /ext del PHP. no vamos a enseñar a instalar el PHP o el Apache. En el PHP. ?> 528 . Para comprobar que todo está funcionando correctamente. extension = php_saprfc.Como este es un libro sobre NetWeaver y no sobre PHP (Para eso está. Instalando el SAPRFC Simplemente debemos descomprimir el archivo .ini debemos agregar la siguiente línea. lo que vamos a hacer es configurar el SAPRFC e integrarlo con NetWeaver.ZIP y copiar el archivo php_saprfc. simplemente llamamos a una página con el comando PHP_INFO(). <?php phpinfo(). ni tampoco a programar en PHP. Reiniciamos el servicio del Apache y estamos listos para comenzar.dll. El Arte de Programar PHP).dll. un emulador de SE16. es crear nuestra clase para poder logearnos a NetWeaver. La llamamos Login_Class. PRINT("<BR><TABLE BORDER='1' BORDERCOLOR='BLUE' BGCOLOR='WHITE'>").SE16 Emulator</H1>"). PRINT("<TR><TD>Server</TD><TD><INPUT TYPE='TEXT' NAME='Server'></TD></TR>").php' METHOD='POST'>"). function Login_Page() { PRINT("<DIV ALIGN='CENTER'><BR><BR><BR><BR><H1>PHP & SAP . Lo primero que debemos hacer. PRINT("<TR><TD>Client</TD><TD><INPUT TYPE='TEXT' 529 . $rfc. es lo primero que hice yo con PHP y NetWeaver). PRINT("<TR><TD>System Number</TD><TD><INPUT TYPE='TEXT' NAME='Sysnum' SIZE='3'></TD></TR>").php <?php Class Login { var $Login.Estableciendo la comunicación con NetWeaver Vamos a crear un ejemplo simple (En realidad. PRINT("<FORM ACTION='index. "PASSWD"=>$Pass. IF ( !$this->rfc ) { ECHO "The connection fails with the following 530 . } function Log_In($Server. PRINT("<TR><TD>Password</TD><TD><INPUT TYPE='PASSWORD' NAME='Pass'></TD></TR>").$User. "USER"=>$User.$Pass) { $this->Login = array ("ASHOST"=>$Server. PRINT("<TR><TD COLSPAN='2' ALIGN='CENTER'><INPUT TYPE='SUBMIT' value='Log In' NAME='LOG_IN'>").$Client. "CODEPAGE"=>"1404"). PRINT("<TABLE>"). } function RFC_Connection($Login) { $this->rfc = saprfc_open($Login). return $this->Login.NAME='Client' SIZE='3'></TD></TR>"). PRINT("</FORM>"). "SYSNR"=>$Sysnum.$Sysnum. PRINT("<INPUT TYPE='RESET' value='Clear'></TD></TR>"). PRINT("<TR><TD>User</TD><TD><INPUT TYPE='TEXT' NAME='User'></TD></TR>"). PRINT("</DIV>"). "CLIENT"=>$Client. donde debemos Nos conectamos a NetWeaver con los parámetros ingresar el Usuario. Ahora.saprfc_error(). <?php Class SE16 { var $fce.php que es la que va hacer todo el trabajo “sucio”. RFC_Connection Reestablecemos la conexión. 531 . Nos muestra la pantalla de logeo. } else { return $this->rfc. Password. Número de Sistema y Cliente. Login_Page Log_In ingresados. } } } ?> Lo que hacemos es crear algunas funciones. EXIT.error:". Servidor. debemos crear la clase SE16. saprfc_import ($this->fce. else echo ("Call error: "."/"). saprfc_table_init ($this->fce.saprfc_exception ($this->fce))."FIELDS")."DATA"). if ($rfc_rc != SAPRFC_OK) { if ($rfc == SAPRFC_EXCEPTION ) echo ("Exception raised: "."QUERY_TABLE".". IF (! $this->fce ) { ECHO "The function module had failed. saprfc_table_init ($this->fce. saprfc_table_init ($this->fce. EXIT. $rfc_rc = "".function Show_Table($Table. exit.$Table)."OPTIONS")."DELIMITER".$RFC_Me) { $this->fce = saprfc_function_discover($RFC_Me. } $Table = STRTOUPPER($Table). $rfc_rc = saprfc_call_and_receive ($this->fce). } 532 .saprfc_error ($this->fce)). saprfc_import ($this->fce. "RFC_READ_TABLE"). $i<=$field_row . for ($i=1. $i<=$data_row.$DATA['WA']). $i++) { $FIELDS = saprfc_table_read ($this->fce. ECHO "</TD>".$i). ECHO $FIELDS['FIELDNAME']. $rem = $i % 2. for($i=1. if($rem == 0) { ECHO "<TR BGCOLOR='#ADDEF7'>". } 533 . $field_row = saprfc_table_rows ($this->fce. ECHO "<BR><BR>"."DATA")."FIELDS"."DATA". } ECHO "</TR>".$data_row = saprfc_table_rows ($this->fce. ECHO "Table: " . $i++) { $DATA = saprfc_table_read ($this->fce. $TEST = SPLIT("/". } else { ECHO "<TR BGCOLOR='#FFFFFF'>".$i)."FIELDS"). ECHO "<TR>". ECHO "<TD BGCOLOR='#4D80F6'>". $Table. ECHO "<BR>". ECHO "<TABLE BORDER='1' BORDERCOLOR='BLUE'>". Vamos a analizar algunos puntos clave del código. ECHO $TEST[$j].").”RFC_READ_TABLE”). se conecta con el módulo de funciones RFC_READ_TABLE. obtiene los datos y los muestra utilizando un formato de tabla de HTML. $j++) { ECHO "<TD>". ECHO "</TD>". ECHO "<CENTER>". Show_Table. ECHO "</CENTER>". $j<$field_row. PRINT("</FORM>"). 534 . $fce = saprfc_function_discover($rfc. . } ECHO "</TABLE>". PRINT("<INPUT TYPE='HIDDEN' NAME='LOG_IN'><BR>"). } } ?> Aquí tenemos una sola función. esta función recibe el nombre de la tabla que queremos visualizar. PRINT("<FORM ACTION='index. } ECHO "</TR>".for($j=0. .php' METHOD='POST'>"). PRINT("<INPUT TYPE='SUBMIT' value='Back' NAME='Back'>&nbs p. saprfc_import($fce.”DATA”. $DATA = saprfc_table_read($fce. echo($DATA[WA].$Table).$i). Imprimimos el contenido de la tabla especificando el campo.”OPTIONS”).”DATA”).”QUERY_TABLE”. Inicializamos la tabla interna $rc = saprfc_call_and_recieve($fce). Leemos el registro de la tabla por medio de un índice.Verificamos que el módulo de funciones exista. Asignamos el nombre la tabla al parámetro QUERY_TABLE. 535 . $data_row = saprfc_table_rows($fce. Ejecutamos la función y recibimos los parámetros IMPORT o tablas internas de salida. Leemos la cantidad de líneas que tiene la tabla interna.”\n”). saprfc_table_init($fce. php"). Cerramos la conexión con SAP. La primera.saprfc_function_free($fce).text-align: center. include("Login_Class. Ahora.} </style> </head> <body> <?php if(isset($_POST['LOG_IN']) || (isset($_POST['Table']))) 536 .} #login {background: #E5EAF6.php <?php session_start(). es obviamente index.border: 1px solid #C7D3EA. podemos continuar con las páginas PHP. ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF. saprfc_close($fce). Liberamos la función de la memoria. $_SESSION["Client"]. 537 .").php' METHOD='POST'>").$_SESSION["Pass"]). $_SESSION["User"]. } $Login = new Login().$_SESSION["Sysnum"]. $_SESSION["Client"] = $_POST["Client"]. . $Log_Me = $Login->Log_In ($_SESSION["Server"]. PRINT("<FORM ACTION='Operation.php'>Log Out</A>". PRINT("<INPUT TYPE='TEXT' NAME='Table'><BR>"). ECHO "<A HREF='index.{ if(!isset($_SESSION["Server"])) { $_SESSION["Server"] = $_POST["Server"]. PRINT("<INPUT TYPE='SUBMIT' value='Show Table' NAME='Show_Table'> . } else { $_SESSION = array(). $RFC_Me = $Login->RFC_Connection($Log_Me). $_SESSION["Sysnum"] = $_POST["Sysnum"]. ECHO "<CENTER>". $_SESSION["User"] = $_POST["User"]. session_destroy(). ECHO "</CENTER>". . $_SESSION["Pass"] = $_POST["Pass"]. PRINT("</FORM>"). La última página es Operation. ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF. $Login->Login_Page().} </style> </head> <body> 538 .text-align: left.php"). lo que hacemos es llamar a nuestra clase Login para poder conectarnos a NetWeaver y solicitar la tabla que queremos visualizar. include("SE16. } ?> </body> </html> En esta página. <?php session_start().php").php en donde llamamos a la clase SE16 para mostrar los datos en la tabla.} #login {background: #E5EAF6.$Login = new Login().border: 1px solid #C7D3EA. include("Login_Class. } ?> </body> </html> Con esto terminamos y podemos ver el programa en ejecución. $RFC_Me = $Login->RFC_Connection($Log_Me). $_SESSION["Client"]. if(isset($_POST['Table'])) { $Table = $_POST['Table'].$RFC_Me).$_SESSION["Pass"]).<?php $Login = new Login(). $SE16 = new SE16(). $Log_Me = $Login>Log_In($_SESSION["Server"]. 539 . $SE16->Show_Table($Table. $_SESSION["User"].$_SESSION["Sysnum"]. 540 . .org/frs/download. agrega todo lo que falta a esos dos lenguajes..com/download/ruby/saprfc.exe • SAPRFC-0.Integración Ruby-NetWeaver Introducción Ruby es un lenguaje de programación japonés. • Ruby Versión 1. totalmente orientado a objetos y que hereda las características más importantes de Perl y Python.piersharding. llamado SAP::Rfc creado por el genial Piers Harding.piersharding. Como no podía ser de otra forma.so. creado hace más de 11 años por Yukihiro “Matz” Matsumoto. Lo único que necesitamos para poder integrar Ruby con NetWeaver es lo siguiente.gem • SAPRFC.5 http://rubyforge.19mswin32.Y como dice “Matz”.19-mswin32.php/12751/ruby18521.so. existe un conector para Ruby con NetWeaver.com/download/ruby/saprfc-0.gem http://www.win32 http://www.wi n32 541 . Ruby es un lenguaje de fácil aprendizaje.8. 542 . (Para aprender Ruby. solamente vamos a revisar las líneas de código más importantes.19mswin32. Para comprobar la instalación basta con hacer un GEM LIST para obtener la lista. que es bastante poco. pueden comprar “El Arte de Programar Ruby”). Como este no es un libro sobre Ruby.gem y listo. y un pequeño ejemplo (Emulador de SE16) nos tomará solamente 63 líneas. Estableciendo la comunicación con NetWeaver La integración de Ruby con NetWeaver es bastante sencilla.Instalando el SAP::Rfc Simplemente debemos hacer un GEM INSTALL SAPRFC-0. chop!.is_connected().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.discover("RFC_READ_TABLE") print "\nEnter table: " 543 . => "EN".to_i. "\n" # lookup the interface for RFC_READ_TABLE itab = rfc.chop!. # test the connection # print "is_connected: ". :passwd => $Password. rfc. :sysnr :lang :user :trace => $Sysnr. => 1) :client => $Client.chop!.to_i.chop!. => $User.new(:ashost => $Host.chop!. $Table = gets print "\n" itab.value = "|" # do the RFC call rfc.$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.to_s.delimiter.new $Data = Array..hashRows {|field| $Data.value = $Table. "|" end print "\n\n" end print "\nclose connection: ".to_s..strip!) } $Data_Len = $Data.query_table..$Fields_Len print $Data_Split[i].new itab.new $Data_Split = Array.length itab.close().push(field) } $Fields_Len = $Fields.hashRows {|field| $Fields.fields.data. rfc.chop! itab.strip.split("|") for i in 1.new $Data_Fields = Array..length for i in 0.call(itab) $Fields = Array. "\n" print "Exit" 544 .push( field. new(:ashost => $Host. itab.chop! itab.value = $Table. :sysnr => $Sysnr. :trace => 1) Establecemos la conexión pasando los parámetros indicados por el usuario.query_table. require ‘rubygems’ gem ‘saprfc’ require ‘SAP/Rfc’ Llamamos a la librería de SAP::Rfc y especificamos que queremos utilizar el GEM. :client => $Client.Veamos un poco el código. :user => $User.delimiter.chop!. itab = rfc. :lang => "EN".chop!.chop!. rfc = SAP::Rfc. :passwd => $Password.discover("RFC_READ_TABLE") Verificamos que el módulo de funciones exista.to_i.to_i.value = "|" 545 .chop!.chop!. hashRows {|field| $Data.. podemos ver algunas imágenes.$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.to_s.length itab.fields.to_s.call(itab) Ejecutamos la llamada al módulo de funciones. Ahora.split("|") for i in 1.push(field) } $Fields_Len = $Fields. rfc. itab... "|" end print "\n\n" end Imprimimos el resultado en pantalla.strip. 546 .hashRows {|field| $Fields.strip!) } $Data_Len = $Data.$Fields_Len print $Data_Split[i].length Obtenemos los datos que nos retorna la función.push(field.. for i in 0.data.Llenamos los parámetros del módulo de funciones. 547 . Donde conseguir el SAP NetWeaver Sneak Preview El SAP NetWeaver Sneak Preview es la versión para desarrolladores de SAP AG.sdn.sap. • Comprando el libro ABAP Objects : ABAP Programming in SAP NetWeaver de Horst Keller y Sascha Krüger en SAP Press.sap. http://www.sappress.cfm?account=&product=H1934 • Descargandolo desde el SDN (SAP Developer Network – http://sdn.com/product.com) en Download Releases Version https://www. Podemos conseguirla de dos maneras.0 (2004s) – ABAP Trial 548 .com/irj/sdn/go/portal/prtroot/docs/library/ uuid/80fd9a0a-e306-2a10-c896-b84c77c13ed2 SAP NetWeaver Main SAP NetWeaver 7. 549 .sappress. A Cathy Welsh por facilitarme información valiosa sobre WebDynpro. A Craig Cmehil que siempre ha sido un Mentor para mi. puesto que me han apoyado mucho al momento de estar escribiendo este libro. http://www.. a quienes dedico este libro.com/product.cfm?account=&product=H1934 • Next Generation ABAP Development de Rich Heilman y Thomas Jung – SAP Press. • • • • • Mi esposa Milly y mi hija Tammy Luz.Bibliografía y agradecimientos • ABAP Objects : ABAP Programming in SAP NetWeaver de Horst Keller y Sascha Krüger – SAP Press. A Thomas Jung y Rich Heilman (A quienes conocí en Las Vegas TechEd 2007 y gracias a ellos escribí este libro). mis agradecimientos.sappress.cfm?account=&product=H1986 • El Arte de Programar SAP R/3 de Alvaro Tejada Galindo – Lulu Press.. http://www. A Abesh Bathacharjee quien con su amistad y sentido del humor me ayudó a ser más creativo.lulu. Sin orden de importancia. http://www.com/product.com/content/561744 Hay muchas personas a quienes debo agredecer. A Mark Finnern por la confianza en mi que siempre ha demostrado.• • • Al SDN (SAP Developer Network) por haberme eligido como Mentor de SAP. 550 . A Marilyn Pratt por haberme demostrado que “Las abuelitas también pueden rockear”. com http://bpx.sap.com http://www. • • • • • • • • SDN (SAP Developer Network) BPX (Business Process Expert) El Blog Tecnológico de Blag SAP ABAP en castellano SAP Press SAP Help SAP Marketplace http://sdn. quiero agregar algunos enlaces web que pienso que pueden ser bastante útiles.sap-press.sap4.com Alvaro Tejada Galindo’s SDN Blogs https://www.com/irj/sdn/weblogs?blog=/pub/u/4802 4 • SAP http://www.sap.sap.sap.com http://service.sap.com http://www.com http://atejada.com 551 .Enlaces Web Para terminar.sdn.blogspot.com http://help.sap.