Professional Documents
Culture Documents
Sobre el Autor
Alvaro Tejada Galindo se inici en el mundo de la programacin a los 20 aos. Sus primeros lenguajes fueron C++ y Visual Basic 6.0 lo cuales aprendi de manera autodidacta gracias a libros, foros, tutoriales y cdigos fuente. A lo largo de los aos, fue agregando nuevos lenguajes a su coleccin, tales como Java, QBasic, Pascal, Delphi, HTML y JavaScript. Fue cuando tena 24 aos, que conoci el mundo del SAP, puesto que entr a hacer sus prcticas en TSNet Global, en donde trabaj por espacio de 2 aos, con grandes proyectos en empresas como Telefnica 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 aos en la Consultora ActualiSap (Consultora Chilena), en donde adems de dos exitosos proyectos de implementacin en Suez Enegy Per y el Aeropuerto Jorge Chvez, dict un curso interno de IDocs 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 Crdito del Per.
Su experiencia en SAP y ABAP es de 5 aos 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 artculos sobre ABAP, HR, Integracin de PHP con SAP e Integracin de Ruby con SAP. Adems, es Moderador en los foros del SDN y Mentor de SAP para Amrica Latina y el resto del mundo. Pueden leer sus artculos en la siguiente direccin: http://tinyurl.com/jnlfd http://atejada.blogspot.com
Indice
Conociendo el entorno SAP NetWeaver Introduccin Ingresando al sistema Conociendo las transacciones ms importantes El Men de SAP NetWeaver Diccionario de Datos Introduccin Elementos del Diccionario de Datos Creando una tabla Creando un dominio Creando un elemento de datos Creando una vista de actualizacin Creando una ayuda de bsqueda Creando una estructura Creando una Vista Programacin en ABAP Introduccin Estructura de un programa ABAP Declaracin de variables y tablas internas Seleccin de datos Lectura de datos en tablas internas Operadores de comparacin Operaciones en tablas internas Copiar tablas internas Ordenar tablas internas Estructuras de Control Trabajando con Cadenas de Texto Variables de Sistema Modularizacin de programas Depuracin de programas Programas de ejemplo SapScript Introduccin Creando un formulario Crear una pgina 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 pgina Crear prrafo por defecto Creando un programa de impresin Diseando el formulario Ejecutando el formulario Debugger en SAPScript SmartForms Introduccin Creando un estilo Creando un formulario Creando un programa de impresin Ejecutando el formulario Crear una tabla Screen Painter y Menu Painter Introduccin Screen Painter Controles del Screen Painter Ejemplo de Screen Painter Menu Painter Agregando componentes Programacin avanzada en Dynpros MatchCodes dinmicos Eliminar registros en un Table Control Escritura/Lectura en un Table Control Trabajando con subScreens Utilizando listas desplegables Leyendo datos de un Dynpro Mdulos de Funcin y BAPIS Introduccin Mdulos de Funcin Creando nuestra primera funcin Llamando funciones desde un programa Introduccin BAPIS ALV (ABAP List Viewer) Introduccin 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
Introduccin Qu es la Orientacin a Objetos? Conceptos bsicos 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 Imgenes en Dynpros Leer PDFs Comprimir (zip) archivos Crear un Control de Texto WebDynpro Introduccin Creando nuestro primer WebDynpro BSP Introduccin Creando nuestro primer BSP ABAP y XML Scripting in a Box SAPLink Integracin PHP-NetWeaver Introduccin Instalando el SAPRFC Comunicndonos con NetWeaver Integracin Ruby-NetWeaver Introduccin Instalando el SAP:Rfc Comunicndonos con NetWeaver Donde conseguir el SAP NetWeaver Sneak Preview Bibliografa 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
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.
En esta ventana es donde ingresaremos nuestro usuario y password. En la caja de texto de Language (Idioma), solamente podremos ingresar EN NSP. Ingls o DE Alemn. El ingls 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 cdigos generalmente de 4 dgitos 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
11
Aqu podemos crear nuestro programas o includes (Programas no ejecutables que se incluyen dentro de programas ejecutables).
12
2.- SE11 (Diccionario ABAP) En esta transaccin podremos crear, visualizar o modificar Tablas, Vistas, Dominios, Estructuras y Ayudas para Bsqueda.
13
3.- SE16 (Browser de Datos) Es donde visualizamos los datos incluidos en Tablas o Vistas.
14
15
Podemos definir pginas, ventanas, tipos de prrafo, mrgenes, tabuladores, insertar imgenes. Por lo general se utilizan para generar Cartas de Pago a Bancos, Facturas, Cheques, Certificados. 5.- SmartForms (Form Painter Avanzado) Nos permite crear formularios de Impresin. El SmartForms es la nueva versin del SapScript. Se puede utilizar cualquiera de los dos, aunque depende de cada desarrollador.
16
6.- SE51 (Screen Painter) Nos permite disear pantallas para crear programas interactivos.
17
18
8.- SE37 (Function Builder) Nos permite crear funciones para utilizar en nuestros programas, as como modificar o visualizar funciones ya creadas.
19
20
Equivale a hacer clic en la tecla Enter. Aqu es donde se escribe la transaccin a la cual queremos acceder. Si escribimos /n antes de la transaccin, accederemos a ella en la misma ventana. Si escribimos /o antes de la transaccin, accederemos a ella en una nueva ventana. Ej: /nSE38 /oSE16.
Grabar. Retroceder una pantalla. Salir del programa o transaccin. Cancelar el programa o transaccin. Imprimir. Buscar. Buscar ms.
21
Se habilitan en Tablas y sirven para avanzar o retroceder registros. Abre una nueva ventana o sesin del NetWeaver. Crea un acceso directo en el escritorio. Ayuda. Configuraciones GUI.
22
Diccionario de Datos
Introduccin
El Diccionario de Datos en NetWeaver, es el repositorio en el cual se almacenan todas las tablas, elementos de datos, dominios, estructuras, ayudas de bsqueda. Vamos a dar un breve repaso de todos los conceptos que intervienen en el diccionario de datos, as como la manera de crear cada uno de sus diferentes componentes. Cabe destacar, que en NetWeaver, todo es manejado por tablas, es decir, todos los programas, funciones, includes y elementos del diccionario son almacenados en tablas. Por lo tanto, NetWeaver cuenta con 63,348 tablas standard...Y eso que hablamos de la versin Sneak Preview, la versin real del NetWeaver debe tener por lo menos el doble o triple de tablas.
Tablas Reunidas (Pooled Tables): Posee una relacin de muchos a uno con una tabla de la Base de Datos. Es decir, por una tabla que existe fsicamente en la base de datos, existen muchas tablas en el Diccionario de Datos. Muchas tablas Pool, se encuentran almacenadas fsicamente en la Base de Datos en tablas llamadas Pool Tables. Este tipo de tablas, son definidas por SAP.
Tablas Racimo (Cluster Tables): Una tabla racimo, es similar a una Pool Table. Poseen una relacin de muchos a uno con una tabla de la Base de Datos. Muchas tablas racimo son almacenadas fsicamente en la Base de Datos en tablas llamadas Table Cluster. Este tipo de tablas son definidas por SAP y su uso se limita a tablas que son accedidas constantemente, como las tablas del sistema.
2.- Componentes de una tabla Las tablas estn compuestas por campos, y cada campo debe de estar asignado a un Elemento de Datos o a un Tipo Predefinido. Los Elementos de Datos, contienen los nombres del campo, as como tambin almacenan los valores de la ayuda en lnea. Una definicin de Elementos de Datos, requiere a su vez de un Dominio. Los Dominios, contienen las caractersticas tcnicas de un campo, tales como su longitud y su tipo de dato.
24
Tipos de Datos para Dominios Tanto los Elementos de Datos como los Dominios, son reutilizables. Lo que significa que pueden estar definidos en ms de una tabla, sin que esto genere algn tipo de conflicto.
25
En esta transaccin podremos visualizar, modificar, eliminar o crear los siguientes elementos: Tablas Transparentes Vistas Estructuras Dominios Elementos de Datos Ayudas para bsqueda
1.- Creando una tabla Para propsitos del libro, vamos a crear 2 tablas, llamadas ZLENGUAJES_PROG y ZENTORNOS_PROG. Con estas
26
tablas, vamos a trabajar todos los ejemplos del libro, as que es muy importante que las creen para poder seguir los ejemplos con mayor facilidad. Como se habrn dado cuenta, ambas tablas comienzan con el prefijo Z, puesto que es la nica restriccin que nos da NetWeaver al momento de crear cualquier elemento o componente. Para crear nuestra primera tabla, hacemos lo siguiente: Escribimos el nombre de la tabla que queremos crear.
En este momento, se nos presenta una ventana, en la cual, deberemos ingresar una descripcin para la tabla, adems de una clase de entrega y definir si la tabla puede ser mantenida desde la transaccin SE16 o por algn programa externo.
27
Clase de Entrega Casi en un 99% de las veces, se utiliza la clase de entrega A, as que es la que vamos a utilizar nosotros. En todo caso, la nica que podramos utilizar adems de esta, son los tipo C y L. Tambin debemos escoger el tipo de Mantenimiento que se le va a dar a la tabla. En nuestro caso, escogeremos la opcin Display/Maintenance Allowed para poder generar una Vista de Actualizacin ms adelante. Cuando grabemos, nos encontraremos con una ventana muy comn en NetWeaver. Esta ventana, nos pide asociar nuestra tabla a un Package (Paquete), que nos es ms que una tabla donde se organizan los desarrollos por tipos. Tenemos dos opciones, o
28
utilizamos el paquete $TMP que es local y por lo tanto no transportable (Es decir, no puede salir del ambiente DEV de desarrollo), o podemos crear nuestro propio Package en donde almacenaremos todos los componentes que creemos en el libro. Obviamente, vamos a crear nuestro propio Package, as que debemos hacer lo siguiente: Abrimos una nueva ventana o sesin con /oSE80 (Object Navigator). Y escogemos la opcin Package de la lista.
29
NetWeaver nos solicita que ingresemos una Orden de Transporte para almacenar nuestro nuevo Package, presionamos el botn Create Request.
30
Una vez creada y asignada la Orden de Transporte, presionamos el botn Continue o presionamos Enter.
31
Atributos del Package ZARTE_PROGRAMAR Regresamos a la sesin donde tenamos la tabla y hacemos un clic en el botn del parmetro Package.
32
Podemos ingresar el nombre del Package, o solicitar que se muestren todos los disponibles, presionando el botn Start Search o presionando la tecla Enter.
En nuestro caso, lo mejor es escribir Z* para que nos muestre solamente los paquetes creados por nosotros o por el sistema (Definidos para los usuarios).
Escogemos nuestro Package con un doble clic para que quede asignado a nuestra tabla.
33
Presionamos el botn Save. Y nos va a aparecer la ventana solicitando una Orden de Transporte. Como creamos una orden al momento de crear el Package, entonces la misma orden aparecer por defecto. Presionamos el botn Continue o la tecla Enter.
Ahora, podemos continuar con la creacin de nuestra tabla. Debemos ir a la pestaa Fields (Campos), para poder agregar los campos necesarios para nuestra tabla.
34
El primer campo que vamos a utilizar es el MANDT, que identifica al ambiente en el cual estamos trabajando (Y que es un campo llave). El segundo campo, se llamar Id, y ser el encargado de identificar a cada uno de los registros (Tambin es un campo llave).
Como se darn cuenta, en el grfico no he llenado el campo Data Element (Elemento de Datos), para el campo Id. Esto es porque vamos a utilizar un Predefined Type (Tipo Predefinido). Hacemos clic en el botn Predefined Type. Y como podemos ver, la interfaz de la pantalla cambia un poco.
35
Queremos que el tipo de dato sea CHAR y tenga una longitud de 3, adems, agregamos una pequea descripcin del campo.
El siguiente campo tambin necesita un tipo predefinido, as que lo llamamos Nombre y lo definimos como un CHAR de longitud 15.
El siguiente campo se llamar Entorno. Este estar relacionado poder crearla, con una de tabla que con llamaremos la tabla ZENTORNOS_PROG, as que abrimos otro modo para antes continuar ZLENGUAJES_PROG.
Al igual que en la tabla ZLENGUAJES_PROG, los 2 primeros campos sern Mandt y Id.
36
El tercer campo, se llamar Nombre, y no tendr asociado un Tipo Predefinido, sino que contar con un Elemento de Datos y un Dominio. Para esto, abrimos una nueva ventana en la SE11 y nos posicionamos en Domain (Dominio).
este
Dominio,
lo
llamaremos
ZD_ENT_NAME.
37
3.- Creando un Elemento de Datos Una vez creado el Dominio, pasamos a crear nuestro Data Element (Elemento de Datos). En la misma transaccin, nos posicionamos en Data Type (Tipo de Dato).
Lo llamaremos ZE_ENT_NAME. Se dar cuenta, de que al momento de presionar el botn Create, aparece una ventana preguntndonos por el Tipo de Dato que queremos crear. Lo dejamos como Data Element y presionamos Enter. Llenamos los datos como se muestra en la figura, utilizando el Dominio que creamos.
38
Ahora, debemos pasar a la pestaa Field Label (Etiqueta de Campo), que no es ms que la descripcin del Elemento de Datos. La llenamos como se muestra en la figura. Grabamos y activamos.
Como estbamos ingresando Tipos Predefinidos, debemos presionar el botn Data Element ingresar el nombre de nuestro Elemento de Datos. . E
Grabamos y ahora debemos llenar los datos de Technical Settings (Caratersticas Tcnicas) Goto Technical Settings o presionar Crtl + Shift + F9. Y luego debemos
39
El campo Data Class (Clase de Datos) especifica el rea fsica en la cual se va a crear la tabla. Para nosotros, el valor por defecto siempre ser APPL0. El campo Size Category (Categora de Tamao), determina la cantidad de espacio que se reservar inicialmente para la tabla, en nuestro caso, nuestra tabla no contendr mucho datos, as que 0 es la opcin a tomar. Grabamos y retrocedemos para poder acceder al Enhacement Category. 40
Esto sirve para definir si la tabla puede ser modificada con campos adicionales. En nuestro caso, le decimos que no, puesto que son tablas que hemos creado como ejemplo para el libro. Grabamos y activamos. Regresamos a nuestra tabla ZLENGUAJES_PROG y presionamos el botn Data Element, para poder ingresar nuestro Elemento de Datos para el campo Entorno. Nos posicionamos sobre el campo Entorno y presionamos el botn Foreign Keys (Llaves Forneas) . Esto nos
41
En el campo Check Table (Tabla de Verificacin), escribimos el nombre de nuestra tabla ZENTORNOS_PROG. Y presionamos Enter.
El sistema nos propone crear una asignacin entre las tablas, presionamos Yes (S) o presionamos Enter.
42
Recibimos este mensaje, porque la llave completa de la tabla ZENTORNOS_PROG ZLENGUAJES_PROG. Dejamos la ventana, como se muestra en la figura. no existe en la tabla
El ultimo campo, se llama CONEX_SAP y determina si el lenguaje posee algn tipo de conexin con SAP. Para esto,
43
Como ven, es simplemente un CHAR de 1. Ahora, pasamos a la pestaa Value Range (Rango de Valores). Y llenamos solamente dos valores.
44
De vuelta en la tabla ZLENGUAJES_PROG, agregamos el campo CONEX_SAP con su respectivo elemento de datos.
Ahora que tenemos nuestras dos tablas listas, es hora de agregar algunos datos. Nos vamos a la transaccin SE16 (Browser de Datos). Colocamos el nombre de nuestra tabla de entornos, y presionamos el botn Create Entries (Crear Entradas) presionamos F5. o
Ingresamos algunos cuantos valores. Y grabamos con el botn Save (Guardar) o presionamos Crtl. + S.
46
Una vez que hemos terminado de insertar registros, retrocedemos presionando el botn Back (Atrs) o presionando el botn F3.
Para poder ver los registro que hemos creado, podemos presionar el botn Table Contents (Contenido de Tabla) o presionar Enter.
En esta ventana, podemos hacer un filtro ya sea por Id o por Entorno. En nuestro caso, queremos ver todos los valores, as que dejamos esos campos en blanco. Presionamos el botn Execute (Ejecutar) o presionamos F8.
47
Tenemos 3 registros grabados en la base de datos. Ahora, es el turno de la tabla ZLENGUAJES_PROG. Seguimos el mismo procedimiento.
Cuando se posicionen en el campo Entorno, se darn cuenta de algo interesante. Aparece un pequeo botn al final del campo, lo cual nos indica que existen valores de los cuales podemos escoger. Para esto debemos hacer clic en ese botn o presionar F4.
48
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. Cabe destacar que los valores que estn en la tabla ZENTORNOS_PROG, son los nicos valores vlidos, es decir, si ingresamos cualquier otro valor, el sistema nos mostrar un mensaje de error.
49
Seguramente, les parecer que ingresar los datos as, es un poco tedioso...No se preocupen, que ahora vamos a crear una vista de actualizacin. 3.- Creando una Vista de Actualizacin Para crear nuestra vista de actualizacin, debemos regresar a la transaccin SE11 y modificar la tabla ZLENGUAJES_PROG. En el men, vamos a Utilities (Utilidades) Table Maintenance Generator (Generador de Mantenimiento de Tabla). Llenamos la ventana como se muestra a continuacin.
50
Presionamos el botn Find Scr. Number(s) (Buscar Nmero(s) de Pantalla) o presionamos Shift + F7.
En esta ventana, siempre escogemos la primera opcin Propose Screen Number(s) (Proponer nmero(s) de Ventana).
51
o presionamos
Se nos muestra una pantalla ms amigable para el ingreso de datos, pero como se darn cuenta, los dos primeros campos aparecen como
52
+. Esto es porque al ser Tipos Predefinidos, no poseen un texto descriptivo. Esto lo podemos solucionar fcilmente regresando a la transaccin SE11 y al Generador de Mantenimiento de Tabla.
Debemos hacer clic tanto en el Overview Screen (Ventana de Vista general) como en el Single Screen (Ventana sencilla). Veamos primero en el Overview Screen.
53
Seguramente esta pantalla los asusta un poco, pero no se preocupen, que por el momento no vamos a hacer nada con esto, puesto que es cdigo generado automticamente por el NetWeaver. Debemos hacer clic en el botn Layout (Disposicin) cabeceras que tienen un +. .
La pantalla del Screen Painter es la que nos interesa, sobre todos las
54
Debemos hacer un clic en el botn Display <-> Change (Mostrar <> Cambiar) o presionar F1.
Ahora, nos colocamos sobre la primer columna y en la ventana que dice Text (Texto), escribimos lo siguiente
Y en la segunda columna:
Grabamos, activamos y retrocedemos dos veces hasta regresar a la ventana del Generador de Mantenimiento de Tabla. Hacemos doble clic en Single Screen.
55
Y repetimos la operacin, modificando los smbolos +. Grabamos, activamos y regresamos nuevamente. Una vez hecho esto, nos vamos a la transaccin SM30 y veremos que los smbolos + han sido reemplazados por los textos correctos.
Ahora, para hacer las cosas ms interesantes y poder trabajar mejor los ejemplos del libro, regresamos a la transaccin SE11 para crear una nueva y ltima tabla con las siguientes caractersticas.
56
La tabla se llamar ZPROGRAMAS y contendr algunos programas que hemos hecho utilizando los lenguajes de programacin que hemos creado.
En otra ventana, creamos un dominio para el cdigo del lenguaje de programacin, llamado ZD_ID_LENGUAJE.
Ahora,
creamos
un
Elemento
de
Datos
llamado
ZE_ID_LENGUAJE.
57
Para que esto funcione correctamente y podamos hacer una asociacin entre las tablas debemos ZPROGRAMAS modificar la y tabla ZLENGUAJES_PROG,
58
Luego de haber grabado y activado, regresamos a ZPROGRAMAS y nos posicionamos en el campo Id y presionamos el botn Foreign Keys .
59
Grabamos, actualizamos las Caractersticas Tcnicas y la Categora de Amplicacin y activamos la tabla. Como solamente hemos asignado el campo Id a nuestra tabla, al momento de querer elegir un lenguaje de programacin, solamente vamos a ver el cdigo, lo cual no nos va a ayudar de mucho, as que hora de crear una ayuda de bsqueda. 4.- Creando una Ayuda de Bsqueda Para esto, en una nueva ventana, vamos a la transaccin SE11. Y escogemos la opcin Seach Help (Ayuda de bsqueda).
60
Como pueden ver, el campo Nombre tiene asignamos un elemento de datos, as que nuevamente, creamos un Dominio y un Elemento de Datos como se muestra a continuacin.
61
Grabamos y activamos nuestra ayuda de bsqueda y la probamos con presionando el botn Test (Prueba) o presionando F8.
62
En esta ventana, podemos filtrar por Id o por Nombre del lenguaje, en este caso, presionamos Enter porque queremos ver todos los registros disponibles.
Nuestra ayuda de bsqueda est terminada, as que regresamos a la tabla ZPROGRAMAS a la pestaa Entry Help/Check (Entrada de Ayuda/Verificacin).
63
64
Como podemos ver, al hacer F4 en el campo Id, podremos ver tanto el cdigo como el nombre del Lenguaje. Finalmente, nuestra tabla contendr los siguientes registros.
Con esto terminamos y podemos crear una estructura, que no es otra caso que una tabla que solamente contiene una cabecera, es decir, no puede almacenar registros. Esto nos va a ser til al momento de desarrollar nuestros programas, puesto que vamos a poder contar con la estructura sin utilizar memoria adicional de la base de datos. 5.- Creando una Estructura En la transaccin SE11, en el campo Data type, creamos nuestra estructura llamada ZSLENGUAJES_PROG.
65
, se nos
Utilizamos
los
mismos
componentes
que
en
la
tabla
ZLENGUAJES_PROG, aunque quitamos el campo MANDT. Grabamos y activamos. Nos va a pedir, el Enhacement Category (Categora de ampliacin), lo agregamos para poder activar.
6.- Creando una Vista Dentro de la transaccin SE11, creamos nuestra vista en el campo VIEW (Vista). Llamada ZVLENGUAJES_PROG.
66
En la ventana que aparece, elegimos Database view (Vista de Base de Datos). Los dems tipos no los vamos a ver en este libro, puesto que el Database view es el ms utilizado.
Primero, debemos de llenar los campos que vamos a utilizar para relacionar las tablas que vamos a utilizar en la vista, en este caso, ZPROGRAMAS y ZLENGUAJES_PROG.
67
En la pestaa View Flds (Campos de la Vista). Definimos los campos que queremos que se muestren en la vista.
Grabamos y activamos. Los mensajes de advertencia, podemos obviarlos. Una vez que la Vista est activa, podemos comprobar los valores presionando el botn Contents (Contenidos) + Shift + F10. Se darn cuenta de que el sistema no enva a la transaccin SE16. o presionando Ctrl.
68
Con esto, terminamos el captulo dedicado a Diccionario de Datos. Ahora, ya pueden crear sus propias tablas, elementos de datos, dominios o vistas.
69
Programacin en ABAP
Introduccin
ABAP (Advances Business Application Programming), es el lenguaje de programacin propietario de SAP AG, 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, lo cual nos permite hacer modificaciones que otro tipo de sistemas seran imposibles. El ABAP, viene a ser una especie de nieto del COBOL (Common Object Business Oriented Language), que era muy utilizado para el desarrollo de aplicaciones empresariales. En cuanto a la sintaxis de lenguajes, podemos tomarlo como un hbrido entre COBOL, PASCAL y SQL Server. Hasta la versin 45B, el ABAP, era un lenguaje procedural, aunque con el tiempo se el agregaron funcionalidades para convertirlo en un lenguaje orientado a objetos, por lo cual al momento de programar, se pueden mezclar ambas tecnologas sin mayores problemas. El NetWeaver actualmente est en la versin 7.0.0, lo cual significa que nos permite trabajar con ABAP Objects de manera muy completa, aunque como es de suponerse, en versiones posteriores de NetWeaver, se adicionarn algunos componentes extras. En el presente captulo, vamos a revisar los principales componentes del ABAP, as como la estructura de los programas que se crean con el.
70
Cuando presionamos el botn Create (Crear), el sistema nos mostrar la siguiente ventana, en donde debemos escoger el Type (Tipo de programa) y el Status (Estado) asociado.
71
En Type (Tipo) siempre escogemos Executable program (Programa ejecutable) y en Status (Estado), elegimos SAP Standard Production Program (Programa Standard SAP para Productivo). Al presionar el botn Save cual queremos asignar , nos va a pedir el paquete al el desarrollo, elegimos
ZARTE_PROGRAMAR. Y cuando nos pida la orden de transporte, elegimos la creamos puesto que se nos muestra por defecto (Siempre y cuando no hayamos creado otras ordenes). El sistema, nos enva al Editor ABAP, que es donde vamos a poder crear nuestros programas. Debemos tener claro, que existen ciertos comentarios, que debemos colocar en todos nuestros programas, para poder definir algunos bloques importantes.
72
En el espacio de comentario, debemos incluir por ejemplo, quien est creando el programa y cuando.
La primera y nica lnea que nos muestra el editor es REPORT y el nombre de nuestro programa. Esto indica que se trata de un programa ejecutable. Para empezar, vamos a hacer un programa muy simple, que simplemente solicite al usuario un texto y lo imprima en pantalla, luego de esto, veremos la sintaxis de ABAP y podremos hacer programas ms complejos.
73
*&----------------------------------------------------* *& Report ZDUMMY_PRIMER_PROGRAMA * * * *&----------------------------------------------------* *& Creado por: Alvaro "Blag" Tejada Galindo. *& Fecha creacin: 14 de Noviembre del 2007 REPORT ZDUMMY_PRIMER_PROGRAMA.
*&----------------------------------------------------*
*=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRUEBA WITH FRAME TITLE TEXT-T01. PARAMETERS: TEXTO(30) TYPE C. SELECTION-SCREEN END OF BLOCK PRUEBA. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. WRITE: TEXTO. * *=====================================================* * *=====================================================*
El SELECTION-SCREEN BEGIN OF BLOCK, nos permite definir un espacio en donde van a ir los parmetros de entrada de nuestro programa. PRUEBA, es el nombre que le estamos asignando al bloque de parmetros. WITH FRAME TITLE, significa que el rea de los parmetros de seleccin va a estar rodeados por un marco y TITLE, significa que va a contar con un ttulo definido por nosotros, en este caso
74
TEXT-T01. TEXT-T01, lo podemos separar en dos partes TEXT, que nos indica que es un texto del sistema y T01, es el nombre de dicho texto. Para poder modificarlo, simplemente deberemos hacer doble clic en el texto. Si no lo hemos creado, nos aparecer la siguiente ventana:
Simplemente, ingresamos el texto, grabamos y activamos. Dentro del bloque que hemos definido para los parmetros, podemos utilizar 2 tipos de parmetros: PARAMETERS solamente un valor. SELECT-OPTIONS Son parmetros compuestos que aceptan un rango de valores. 75 Son parmetros simples que aceptan
El parmetro que hemos utilizado en este programa, es un CHAR de 30 caracteres. TEXTO(30) TYPE C. Si activamos y ejecutamos el reporte (Presionando la tecla F8), veremos el parmetro de entrada que definimos.
Ahora, si queremos cambiar el texto que muestra nuestro parmetro, deberemos de ingresar al siguiente men. Goto Text Elements Selection Texts.
76
Aqu, deberemos de ingresar el texto que queremos que tenga nuestro parmetro, lo grabamos, lo activamos y listo.
77
El START-OF-SELECTION, nos indica que va a comenzar la ejecucin de nuestro programa, es aqu donde colocamos toda la lgica. WRITE: TEXTO, significa que vamos a escribir en la pantalla, el valor que hemos ingresado en el parmetro de entrada TEXTO.
78
Aqu estamos diciendo que vamos a crear una variable llamada TEXTO, y que va a ser de tipo C (Caracter). Adems, podemos especificar su tamao. DATA: TEXTO(30) TYPE C. Entre los tipos de datos que nos ofrece el ABAP, 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, podemos utilizar campos de tablas para poder hacer la declaracin de variables. 4 8 8 0 0 0.0 1 X00 6 000000 1 1 8 Space 000 000000000
79
DATA: V_CARRID TYPE SPFLI-CARRID. En este caso, estamos declarando una variable que va a ser exactamente igual que el campo CARRID de la tabla SPFLI. Por lo tanto, V_CARRID es un CHAR de 3 caracteres. Ahora veamos las tablas internas, que son uno de los elementos ms valiosos del ABAP. Las tablas internas, son tablas temporales que existen solamente en el mbito del programa que las cre y permiten almacenar informacin para luego poder manipularla sin tener que acceder mltiples veces a la base de datos. En versiones anteriores, podamos utilizar la siguiente sintaxis: DATA: BEGIN OF TABLA OCCURS 0, END OF TABLA. Con la introduccin de NetWeaver, esto no es posible, as que de ahora en adelante, vamos a utilizar y aprender solamente las nuevas sintaxis que se nos ofrecen gracias a la creacin del ABAP Objects. TYPES: BEGIN OF TY_TABLA, END OF TY_TABLA. DATA: T_TABLA TYPE STANDARD TABLE OF TY_TABLA. 80
Primero, debemos crear un TYPE, es decir, un tipo de tabla interna y luego, utilizando el DATA, creamos una tabla interna que haga referencia a nuestro tipo de tabla. Para los que ya conocen ABAP, se darn cuenta de que no hemos creado la tabla con una cabecera. Es decir, no utilizamos ni OCCURS 0, ni tampoco WITH HEADER LINE. Esto es porque, en ABAP Objects, est prohibido utilizar cabeceras o workareas. Para los que no conocen ABAP, en versiones anteriores, podiamos crear tablas internas con lneas de cabecera, lo cual facilitaba la lectura de datos, pero que al mismo tiempo ocasionaba problemas de performance. Es por eso, que SAP decici eliminar la cabeceras completamente. Adems de crear tablas internas, de la manera que hemos visto, podemos tambin incluir estructuras completas de Base de Datos. Esto podemos hacerlo de dos maneras, dependiendo de si queremos o no incluir campos adicionales. DATA: T_SPFLI TYPE STANDARD TABLE OF SPFLI. TYPES: BEGIN OF TY_SPFLI. INCLUDE STRUCTURE SPFLI. TYPES: TEST TYPE STRING. TYPES: END OF TY_SPFLI. DATA: T_SPFLI TYPE STANDARD TABLE OF TY_SPFLI.
81
Claro, si queremos crear una tabla interna que tenga datos propios, lo hacemos de la siguiente forma. TYPES: BEGIN OF TY_TEST, NOMBRE(30) TYPE C, EDAD TYPE I, END OF TY_TEST. DATA: TEST TYPE STANDARD TABLE OF TY_TEST. Seguramente se habrn dado cuenta y sobre todo se preguntarn, porque tenemos que utilizar el TYPE STANDARD TABLE, muy simple, porque tenemos disponibles ms tipos de tablas.
TYPES: BEGIN OF TY_TEST, ID(3) TYPE C, NOMBRE TYPE STRING, EDAD TYPE I, END OF TY_TEST. DATA: TEST TYPE STANDARD TABLE OF TY_TEST. DATA: TEST_H TYPE HASHED TABLE OF TY_TEST WITH UNIQUE KEY ID. DATA: TEST_S TYPE SORTED TABLE OF TY_TEST WITH UNIQUE KEY ID
82
Tablas Standard. Puede ser accedida mediante un ndice o Tabla de tipo hashed. De rpido acceso, pero no puede Sorted table. De rpido acceso, siempre est ordenada,
mediante campos. ser accedida mediante un ndice. no puede ser accedida mediante un ndice. En realidad, el uso de tablas Hashed o Sorted, depende del nivel de nivel de datos o de la complejidad del programa, en lo personal, solo he utilizado este tipo de tablas algunas cuantas veces en toda mi carrera.
Seleccin de Datos
Al igual que en SQL, podemos utilizar la clsica sentencia SELECT, para poder seleccionar datos. Aunque en el caso de ABAP, tenemos mayor flexibilidad para poder almacenar los datos, ya sea en Variable o en Tablas internas. En Variables:
DATA: NOMBRE TYPE ZPROGRAMAS-NOM_PROG. SELECT SINGLE NOM_PROG INTO NOMBRE FROM ZPROGRAMAS WHERE ID_PROG EQ '001'.
83
Declaramos una variable llamada NOMBRE del tipo del campo NOM_PROG de la tabla ZPROGRAMAS. Hacemos un SELECT SINGLE para obtener un registro cuyo campo ID_PROG sea igual a 001. En Tablas internas:
TYPES: BEGIN OF TY_PROGRAMAS, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. SELECT NOM_PROG INTO TABLE T_PROGRAMAS FROM ZPROGRAMAS.
En esta caso, creamos un TYPE, luego una tabla interna y finalmente leemos todas las instancias del campo NOM_PROG dentro de nuestra tabla interna. Claro, tambin podemos utilizar INNER JOINS para hacer nuestras consultas.
TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS.
84
DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ).
Ahora, supongamos que tenemos un campo ms en nuestra tabla interna, pero no queremos seleccionarlo, entonces, el SELECT va a estar incompleto y los registros pueden guardarse donde no les corresponde. Esto lo podemos solucionar utilizando un INTO CORRESPONDING FIELDS, que lo que hace es almacenar los registros en los campos correspondientes, aunque claro, esto afecta el performance de nuestros programas, as que lo mejor es evitarlos.
TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS.
SELECT NOMBRE ENTORNO NOM_PROG INTO CORRESPONDING FIELDS OF TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ).
85
86
DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. ENDLOOP.
Al hacer un LOOP AT, lo que hacemos es leer cada uno de los registros almacenados en nuestra tabla interna, y al asignar cada uno de estos registros a nuestro Field-Symbol, lo que estamos haciendo es pasar simplemente la cabecera de ese registro, por lo cual la lectura de la tablas es mucho ms veloz. Finalmente, utilizando un WRITE imprimimos el contenido del campo NOM_PROG. El smbolo / nos sirve para dejar un espacio hacia abajo luego de haber impreso el valor (Equivales a hacer un ENTER).
87
READ TABLE
TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS WITH KEY NOMBRE = 'PHP' ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOM_PROG.
En este caso, al utilizar un READ TABLE, leemos un solo registro de nuestra tabla, como podemos ver, podemos utilizar
88
Operadores de Comparacin
Un proceso muy comn, es el comparar valores entre variables o tablas internas, para esto, contamos con los siguientes comandos. =, EQ <>, NE >, GT <, LT >=, GE <=, LE Igual a Distinto a Mayor que Menor que Mayor igual Menor igual
Ambos tipos de comandos son equivalentes, por lo tanto es lo mismo decir: IF NOMBRE EQ PHP. WRITE:/ Viva PHP!. ENDIF. Que decir: IF NOMBRE == PHP. WRITE:/ Viva PHP!.
89
ENDIF. Para poder afianzar los conocimientos adquiridos hasta el momento, vamos a crear una pequea aplicacin.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLES TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE VARIABLES DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
90
OF T_PROGRAMAS. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. SELECTION-SCREEN END OF BLOCK PRG. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. 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',17 'Entorno',33 'Programa'. WRITE:/ SY-ULINE(45). LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOMBRE,<FS_PROGRAMAS>-ENTORNO, <FS_PROGRAMAS>-NOM_PROG. ENDLOOP. * *=====================================================* * *=====================================================*
91
REPORT indica que estamos creando y ejecutando un programa. ZDUMMY_PRIMER_PROGRAMA es el nombre de nuestro programa. NO STANDARD PAGE HEADING, indica que no queremos que el ttulo del programa se muestre en el output del reporte.
TABLES: ZPROGRAMAS.
TABLES indica que vamos a utilizar una tabla para hacer referencia a un campo en el SELECTION-SCREEN.
TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS.
TYPES indica que vamos a crear un tipo de tabla definido por nosotros.
92
DATA indica que vamos a crear una variable o una tabla interna. T_PROGRAMAS es el nombre de nuestra tabla interna. 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. TY_PROGRAMAS es el nombre del tipo de tabla que creamos y al cual va a hacer referencia nuestra tabla interna.
FIELD-SYMBOLS crea un field-symbol. <FS_PROGRAMAS> es el nombre de nuestro field-symbol. LIKE LINE OF indica que va a representar una lnea de cabecera de una tabla interna. T_PROGRAMAS es la tabla interna de la cual el field-symbol va a representar la cabecera.
SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. SELECTION-SCREEN END OF BLOCK PRG.
SELECTION-SCREEN BEGIN OF BLOCK indica el inicio de un bloque de parmetros. PRG es el nombre del bloque de parmetros. 93
WITH FRAME indica que nuestro bloque de parmetro debe tener un marco (ms que nada un tema de visualizacin). TITLE TEXT indica que el bloque de parmetros debe tener un ttulo. T01 contiene el ttulo. SELECT-OPTIONS indica que es un parmetros con rango de valores. S_ID es el nombre del SELECT-OPTION. FOR indica que hace referencia a un campo de Base de Datos. ZPROGRAMAS-ID es el nombre de la Base de Datos y el campo respectivamente. SELECTION-SCREEN END OF indica el fin del bloque de parmetros.
START-OF-SELECTION.
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.
SELECT indica que queremos seleccionar datos. NOMBRE ENTORNO NOM_PROG son los campos que queremos seleccionar.
94
INTO TABLE indica en que tabla interna queremos guardar los datos. T_PROGRAMAS es la tabla donde vamos a guardar los datos. FROM indica de donde queremos obtener los datos. ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS indica que queremos realizar un INNER JOIN entre estas dos tablas ON indica el parmetro de igualdad de campos del INNER JOIN. ZLENGUAJES~ID = ZPROGRAMAS~ID indica que el campo ID de ambas tablas va a utilizarse como campo de igualdad. WHERE indica el parmetro de restriccin del SELECT. ZPROGRAMAS~ID es el campo por el cual queremos hacer el filtro. 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.
WRITE indica que queremos escribir algo en la pantalla. / indica que luego de escribir en la pantalla queremos hacer un salto de lneas. 1, 17 y 33, indican las posiciones X en las cuales queremos escribir. Lenguaje, Entorno y Programa son los texto que queremos escribir.
95
SY-ULINE(45) es una variable del sistema que nos permite dibujar una lnea. El 45 entre parntesis indica la longitud de la lnea.
LOOP AT indica que vamos a recorrer todos los registros de una tabla interna. T_PROGRAMAS es la tabla interna de la cual vamos a leer los registros. ASSIGNING <FS_PROGRAMAS> indica que vamos a asignar el registro ledo a un Field-Symbol. <FS_PROGRAMAS> es el nombre del Field-Symbol. <FS_PROGRAMA>-NOMBRE es el nombre del campo que queremos escribir en la pantalla. ENDLOOP indica el fn del LOOP. Ahora que ya hemos revisado todo el programa lnea por lnea, podemos ejecutarlo.
96
Si queremos que nuestro programa se vea un poco ms colorido, podemos agregar un par de lneas.
FORMAT COLOR 5. WRITE:/1 'Lenguaje',17 'Entorno',33 'Programa'. FORMAT COLOR OFF. WRITE:/ SY-ULINE(45).
97
FORMAT COLOR indica que queremos pintar el fondo de un color. 5 representa al color verde. FORMAT COLOR OFF indica que ya no queremos seguir pintando el fondo de un color. El reporte quedara as:
Cuando se trabaja con tablas internas, muchas veces se necesita agregar, modificar o eliminar registros (Ya sea porque no nos sirven o porque estn duplicados). Veamos como manejar esto: Agregando registros
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG,
98
NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-ID_PROG. WRITE:/ <FS_PROGRAMAS>-NOM_PROG.
Como vemos, creamos una tabla interna. Pero como esta no tiene cabecera, entonces debemos asignarle una utilizando APPEND INITIAL LINE TO y asignndola a <FS_PROGRAMAS>. Luego, agregamos los valores a la tabla y al momento de leerla con el ndice 1, podemos imprimir los nuevos valores.
99
Modificando registros
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-ID_PROG. WRITE:/ <FS_PROGRAMAS>-NOM_PROG. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. SKIP 1. WRITE:/ 'Modificamos el registro'. SKIP 1.
100
<FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. READ TABLE T_PROGRAMAS INDEX 1 ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-ID_PROG. WRITE:/ <FS_PROGRAMAS>-NOM_PROG.
Tomando el ejemplo anterior, leemos el primer registro y lo asignamos a <FS_PROGRAMAS>. Simplemente escribimos el nuevo valor para que se modifique automticamente. Podrn ver que adems, estamos utilizando la sentencia SKIP, esta sentencia nos permite realizar saltos de lnea. En esta caso solamente 1. Eliminado registros
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>.
101
<FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '007'. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. DELETE T_PROGRAMAS INDEX 1. DELETE T_PROGRAMAS WHERE ID_PROG EQ '006'.
Asignamos dos registros a nuestra tabla interna, y como podemos ver, podemos eliminarlos utilizando ya sea un ndice o uno de los campos como parmetro de bsqueda. Ahora, supongamos que tenemos registros repetidos y queremos eliminarlos sin preocuparnos por el ndice (Puesto que eliminado por campo, eliminaramos todos los registros).
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS.
102
FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS.
Como podemos ver, tenemos dos veces el mismo registro, por lo tanto utilizamos DELETE ADJACENT DUPLICATES para dejar solamente uno de los dos registros. Claro, quizs se podra dar el caso de que solamente el campo ID_PROG est repetido, ms no el campo NOM_PROG. Entonces debemos hacer algo ms.
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS.
103
DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. DELETE ADJACENT DUPLICATES FROM T_PROGRAMAS COMPARING ID_PROG.
Simplemente debemos agregar un COMPARING, con lo cual solamente se toma en cuenta el campo ID_PROG para hacer la validacin de registros repetidos.
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. T_PROGRAMAS_AUX[] = T_PROGRAMAS[].
En
este
caso,
tenemos y
las
dos
tablas
internas ambas
T_PROGRAMAS
T_PROGRAMAS_AUX,
haciendo referencia a TY_PROGRAMAS, por lo tanto, poseen exactamente la misma estructura. Por ello, podemos utilizar el [] para copiar los datos de una tabla a otra.
105
106
Creamos un tipo de tabla llamado TY_PROGRAMAS_AUX al cual le agregamos el campo ID, con lo cual hacemos que ambas tablas internas sean distintas, por lo cual no podemos seguir utilizando el []. En vez de eso, debemos hacer un LOOP y asignar los valores de la tabla T_PROGRAMAS a la tabla T_PROGRAMAS_AUX. Eso est bien para algunos campos, pero si tenemos por decir 20 campos...Entonces debemos utilizar una forma alternativa.
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_PROGRAMAS_AUX, ID TYPE ZPROGRAMAS-ID, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS_AUX. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_PROGRAMAS_AUX TYPE STANDARD TABLE
107
OF TY_PROGRAMAS_AUX. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS, <FS_PROGRAMAS_AUX> LIKE LINE OF T_PROGRAMAS_AUX. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. APPEND INITIAL LINE TO T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. MOVE-CORRESPONDING <FS_PROGRAMAS> TO <FS_PROGRAMAS_AUX>. ENDLOOP.
Cuando utilizamos el MOVE-CORRESPONDING, 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.
108
TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZPROGRAMAS-ID_PROG, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '006'. <FS_PROGRAMAS>-NOM_PROG = 'MP3 Player'. <FS_PROGRAMAS>-ID_PROG = '005'. <FS_PROGRAMAS>-NOM_PROG = 'Web Browser'. SORT T_PROGRAMAS BY ID_PROG ASCENDING. SORT T_PROGRAMAS BY ID_PROG DESCENDING.
Utilizamos la sentencia SORT para ordenar una tabla interna, podemos incluir BY para indicar por cual o cuales campos debera ordenarse y adems podemos indicar si la ordenacin es Ascending (Ascendente) o Descending (Descendente).
109
Estructuras de Control
Como vimos, podemos utilizar un LOOP para recorrer todos los registros de una tabla interna. Pero que pasa si lo que necesitamos es recorrer los posibles valores de una variable? Para estos casos contamos con WHILE-ENDWHILE.
DATA: VAR TYPE I. WHILE VAR LT 10. WRITE:/ VAR. VAR = VAR + 1. ENDWHILE.
Esto significa que mientras la variable VAR sea menor o igual a 10, imprimimos el valor. Aumentamos el valor de VAR de uno en uno, por cada vuelta del WHILE. Tambin tenemos presente el DO-ENDO.
DATA: VAR TYPE I. DO. IF VAR LT 10. WRITE:/ VAR. VAR = VAR + 1. ELSE. EXIT. ENDIF. ENDDO.
110
El DO-ENDDO es un bucle repetitivo que avanza mientras no le digamos que tiene que salir. Utilizando un IF preguntamos si el valor de la variable es menor o igual a 10. En el caso afirmativo imprimimos y aumentamos en uno. Cuando VAR es mayor a 10, salimos del DO-ENDDO utilizando un EXIT. Aunque, tambin podramos haberlo escrito as:
En esta caso, le decimos al DO-ENDO que solo realice el bucle 10 veces. Imprimimos el valor de la variable VAR y la aumentamos en uno. Adicionalmente tenemos los comandos CONTINUE y EXIT, que sirven para continuar en la siguiente iteracin de la estructura de la estructura de control o para salir de la estructura de control completamente.
111
ejemplo PERL), de todos modos nos brinda alguna poderosas herramientas como estas: TRANSLATE Convierte una cadena de texto a Maysculas o Minsculas.
DATA: VAR TYPE STRING. VAR = 'El Arte de Programar'. TRANSLATE VAR TO UPPER CASE. WRITE:/ VAR. TRANSLATE VAR TO LOWER CASE. WRITE:/ VAR.
Con TO UPPER CASE convertimos a Maysculas y con TO LOWER CASE convertimos a Minsculas. CONCATENATE Concatena dos o ms cadenas de texto. Es decir, une cadenas en una cadena ms grande.
DATA: VAR TYPE STRING, VAR_AUX TYPE STRING, VAR_TEXT TYPE STRING.
112
VAR = 'El Arte de Programar'. VAR_AUX = 'SAP NETWEAVER'. CONCATENATE VAR VAR_AUX INTO VAR_TEXT. WRITE:/ VAR_TEXT.
Con el CONCATENATE decimos que los valores de las variables VAR y VAR_AUX se guarden en la variable VAR_TEXT. Aunque claro, si ejecutamos el programa nos daremos cuenta de que no hay ningn espacio entre las dos palabras, esto lo arreglamos fcilmente.
DATA: VAR TYPE STRING, VAR_AUX TYPE STRING, VAR_TEXT TYPE STRING. VAR = 'El Arte de Programar'. VAR_AUX = 'SAP NETWEAVER'. CONCATENATE VAR VAR_AUX INTO VAR_TEXT SEPARATED BY SPACE. WRITE:/ VAR_TEXT.
Simplemente agregamos un SEPARATED BY al final del CONCATENATE, en este caso al utilizar SPACE le 113
estamos diciendo que separe el texto con un espacio en blanco. SPLIT Divide una cadena en subcadenas, dependiendo de un carcter aguja.
DATA: VAR TYPE STRING, VAR_AUX TYPE STRING, VAR_TEXT TYPE STRING. VAR_TEXT = 'SAP NETWEAVER'. SPLIT VAR_TEXT AT SPACE INTO VAR VAR_TEXT. WRITE:/ VAR. WRITE:/ VAR_TEXT.
Utilizamos el SPLIT para dividir la cadena utilizando como aguja un espacio y pasamos los valores a las variables VAR y VAR_TEXT.
TYPES: BEGIN OF TY_CADENAS, VAR(30) TYPE C, END OF TY_CADENAS. DATA: T_CADENAS TYPE STANDARD TABLE OF TY_CADENAS.
114
DATA: VAR_TEXT TYPE STRING. VAR_TEXT = 'SAP NETWEAVER'. 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. Declaramos una variable de tipo STRING y utilizando el SPLIT mandamos las subcadenas a la tabla interna. SHIFT Utilizado con la sentencia DELETING, permite eliminar los espacios o caracteres al inicio o al final de una cadena de texto.
DATA: VAR_TEXT TYPE STRING. VAR_TEXT = ' SAP NETWEAVER '.
SHIFT VAR_TEXT LEFT DELETING LEADING SPACE. SHIFT VAR_TEXT RIGHT DELETING TRAILING SPACE.
La variable VAR_TEXT tiene cinco espacios al inicio y cinco espacios al final del texto. Utilizando el SHIFT LEFT DELETING LEADING eliminamos los espacios en blanco del inicio de la cadena.
115
Utilizando el SHIFT RIGHT DELETING TRAILING eliminamos los espacios en blanco del final de la cadena. CONDENSE Elimina los espacios en blanco, como lo hace el SHIFT, pero toma los espacios del final y del inicio al mismo tiempo.
Con el CONDESE eliminamos los espacios del inicio y del final de la cadena. Con el CONDENSE eliminamos todos los espacios de la cadena. REPLACE Reemplaza una cadena por otra.
DATA: VAR_TEXT TYPE STRING. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'. REPLACE SPACE WITH '/' INTO VAR_TEXT.
116
Con REPLACE decimos que reemplace el espacio en blanco con el caracter /. Aunque solamente va a buscar y reemplazar la primera ocurrencia del espacio. En el segundo caso, queremos que busque todas las ocurrencia de / y la reemplace con un espacio. Si hubiramos dicho que busque las ocurrencia del espacio y las reemplace por un /, nuestro programa haba fallado miserablemente. Porque? Realmente no lo s...Tuvimos una emocionante discusin en el SDN (SAP Developer Network) acerca de esto, pero lamentablemente no pudimos hallar una respuesta adecuada. FIND Busca una subcadena en una cadena.
DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. DATA: VAR_TEXT TYPE STRING. FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. VAR_TEXT = 'SAP NETWEAVER PROGRAMMING'.
117
FIND 'NETWEAVER' IN VAR_TEXT RESULTS RESULT_TAB. IF SY-SUBRC EQ 0. READ TABLE RESULT_TAB INDEX 1 ASSIGNING <FS_RESULT>. WRITE:/ <FS_RESULT>-OFFSET. ENDIF.
Creamos una tabla interna llamada RESULT_TAB de tipo MATCH_RESULT_TAB (Que es un tipo predefinido en ABAP). Cuando utilizamos el FIND para hacer la bsqueda de la subcadena, debemos asignar el resultado a la tabla interna RESULT_TAB y de ella leer la posicin de la subcadena dentro de la cadena. Si quisiramos encontrar todas la ocurrencias de la cadena, deberamos hacer lo siguiente:
DATA: RESULT_TAB TYPE MATCH_RESULT_TAB. DATA: VAR_TEXT TYPE STRING. FIELD-SYMBOLS: <FS_RESULT> LIKE LINE OF RESULT_TAB. VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. FIND ALL OCCURRENCES OF 'SAP' IN VAR_TEXT RESULTS RESULT_TAB. IF SY-SUBRC EQ 0.
118
Incluyendo el ALL OCCURRENCES OF podemos conocer todas las ocurrencias de una subcadena dentro de una cadena. STRLEN Obtiene la longitud de una cadena.
DATA: VAR_TEXT TYPE STRING, LONG TYPE I. VAR_TEXT = 'SAP NETWEAVER SAP PROGRAMMING'. LONG = STRLEN( VAR_TEXT ).
119
sistema. Veamos cuales son las ms importantes. (Todas pueden ser encontradas en la tabla SYST). SY-SUBRC Retorna un valor que determina el estado de las operaciones en ABAP. SY-SUBRC = 0 SY-SUBRC = 4 SY-PAGNO En un reporte de tipo listado, determina el nmero de pgina en la cual nos encontramos. SY-TABIX Dentro de un LOOP, nos indica el nmero de vuelta o iteracin o el ndice del registro que estamos leyendo. SY-LANGU Idioma de trabajo actual. SY-BACTH Nos indica si el programa se est ejecutando en fondo o en modo directo. SY-MANDT Ejecutado con xito. Error. No ha podido ejecutarse.
120
Nos indica el nmero de mandante en el cual estamos trabajando. SY-TCODE El nombre de la transaccin con la cual estamos trabajando. SY-UCOMM Nombre del cdigo de funcin lanzado por un Dynpro o por un men. SY-DATUM Fecha actual del sistema. SY-UZEIT Hora actual del sistema. SY-REPID Nombre del programa que estamos creando o ejecutando. SY-UNAME Nombre del usuario logeado en el sistema.
Modularizacin de Programas
Para que nuestros programas sean ms fciles de mantener y de programas, debemos utilizar funciones para poder modularizarlos.
121
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. Para entender mejor a que nos referimos, vamos a hacer un ejemplo.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLES TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, * *=====================================================* * *=====================================================*
122
ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE VARIABLES DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK PRG WITH FRAME TITLE TEXT-T01. SELECT-OPTIONS: S_ID FOR ZPROGRAMAS-ID. SELECTION-SCREEN END OF BLOCK PRG. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM OBTENER_DATOS. PERFORM MOSTRAR_REPORTE. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
123
*&----------------------------------------------------* *& Form obtener_datos * *&----------------------------------------------------* FORM OBTENER_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. ENDFORM. "obtener_datos
*&----------------------------------------------------* *& Form MOSTRAR_REPORTE * *&----------------------------------------------------* FORM MOSTRAR_REPORTE. WRITE:/1 'Lenguaje',17 'Entorno',33 'Programa'. WRITE:/ SY-ULINE(45). LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/ <FS_PROGRAMAS>-NOMBRE, <FS_PROGRAMAS>-ENTORNO, <FS_PROGRAMAS>-NOM_PROG. ENDLOOP. ENDFORM. "MOSTRAR_REPORTE
Se darn cuenta de que este es el mismo ejemplo que ya habamos desarrollado, aunque ahora, lo hemos modularizado.
124
FORM OBTENER_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. ENDFORM. "obtener_datos
En este caso, las funciones o FORM no hacen ms que encapsular las funcionalidades que habamos desarrollado anteriormente. Aunque de todos modos, nos ayuda a tener un cdigo ms ordenado. Ahora, veamos un ejemplo que utilice las caractersticas de los FORMS.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE VARIABLES DATA: VAR TYPE STRING. *=====================================================* * START-OF-SELECTION * * *=====================================================*
125
*=====================================================* START-OF-SELECTION. PERFORM INICIALIZAR. PERFORM CONVERTIR USING 'U' CHANGING VAR. WRITE:/ VAR. PERFORM CONVERTIR USING 'L' CHANGING VAR. WRITE:/ VAR. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. VAR = 'El Arte de Programar NETWEAVER'. ENDFORM. "INICIALIZAR
*&----------------------------------------------------* *& Form CONVERTIR * *&----------------------------------------------------* FORM CONVERTIR USING P_TIPO CHANGING P_VAR. CASE P_TIPO. WHEN 'U'. TRANSLATE P_VAR TO UPPER CASE. WHEN 'L'. TRANSLATE P_VAR TO LOWER CASE. ENDCASE. ENDFORM. "CONVERTIR
126
En este caso, tenemos dos FORMS, 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. Dentro del FORM CONVERTIR, utilizamos un CASE-ENDCASE para poder determinar el valor del parmetro P_TIPO. En el caso de ser U (Upper), entonces hacemos un TRANSLATE TO UPPER CASE y cambiamos el valor de P_VAR. En caso contrario, si es L (Lower), hacemos un TRANSLATE TO LOWER CASE y cambiamos el valor de P_VAR. Luego de llamar a cada PERFORM, imprimimos el valor de P_VAR.
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, END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * *=====================================================* * *=====================================================*
127
*=====================================================*
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM INICIALIZAR. PERFORM IMPRIMIR_REPORTE TABLES T_PROGRAMAS. *&----------------------------------------------------* *& Form inicializar * *&----------------------------------------------------* FORM INICIALIZAR. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '001'. <FS_PROGRAMAS>-NOM_PROG = 'TETRIS'. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. <FS_PROGRAMAS>-ID_PROG = '002'. <FS_PROGRAMAS>-NOM_PROG = 'POKEMON'. ENDFORM. " inicializar * *=====================================================*
*&----------------------------------------------------* *& Form IMPRIMIR_REPORTE * *&----------------------------------------------------* FORM IMPRIMIR_REPORTE TABLES T_TABLA. LOOP AT T_TABLA
128
En esta caso, nuestro FORM recibe un parmetros TABLES, es decir una tabla interna. Por lo tanto, podemos hacerle un LOOP, asignarla a un Field-Symbol e imprimir sus valores.
Depuracin de Programas
El termino bug en programacin, se refiere a un error o a un evento no planeado dentro de la ejecucin 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 cdigo fuente, utilizar un BREAK-POINT lgico o simplemente escribir /H en la barra de men. Veamos ms a fondo las 3 formas. Pero antes de comenzar, es mejor que hagamos un pequeo 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 clsico 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
Tenemos disponible el cdigo fuente para poder ejecutarlo lnea por lnea, por bloques o continuar con la ejecucin.
132
Pero lo ms 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 cdigo.
Una vez que tenemos el nombre escrito, basta con que hagamos doble clic para poder ver su contenido.
Adems, 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 lnea).
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 botn Change Field Content (Cambiar contenido de campo) .
Para avanzar entre las lneas del cdigo, contamos con los siguientes botones.
134
Si no queremos que nuestro programa se pare cada vez que lo ejecutemos. Debemos reemplazar el Break-Point por un BreakPoint lgico.
Nos posicionamos en la lnea donde queremos que pare el programa. En el men seleccionamos Utilities Breakpoints Set/Delete. O si no presionamos Ctrl. + Shift + F12 o presionamos el botn . 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 lgicos para un programa. Este es un truco que aprend hace un par de aos 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 lgicos, los cuales se almacenan por defecto durante un mes. Podemos cargarlos la prxima vez que ejecutemos el programa, podemos extender su estada por una semana ms 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
CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. WHILE NUMERO GT 0. DIGITO = NUMERO MOD 2. NUMERO = NUMERO DIV 2. SUMA = SUMA + DIGITO * EXPONENTE. EXPONENTE = EXPONENTE * 10. ENDWHILE. P_SUM = SUMA. CONDENSE P_SUM NO-GAPS. ENDCATCH. IF SY-SUBRC = 5. WRITE / 'Error de clculo'. FLAG = 'X'. ENDIF. ENDFORM. " CALCULAR_BINARIO
*&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. WRITE:/ 'El nmero binario de',25 P_NUMERO. WRITE:/ 'es:',5 SUMA_TEXT. ENDFORM. " IMPRIMIR
Este programa convierte un nmero decimal a binario, e incluye un elemento muy interesante, el CATCH.
140
CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. WHILE NUMERO GT 0. DIGITO = NUMERO MOD 2. NUMERO = NUMERO DIV 2. SUMA = SUMA + DIGITO * EXPONENTE. EXPONENTE = EXPONENTE * 10. ENDWHILE. P_SUM = SUMA. CONDENSE P_SUM NO-GAPS. ENDCATCH.
Como podemos ver, el cdigo que convierte el decimal a un binario est encerrado entre las sentencias CATCH-ENDCATCH. En este caso, lo que queremos es que el ABAP capture cualquier error de tipo aritmtico, por lo tanto utilizamos ARITHMETIC_ERRORS. Si hay algn error el valor 5 se pasa a la variable del sistema SYSUBRC, por lo tanto:
Si SY-SUBRC es igual a 5, mostramos un mensaje de error. Y adems utilizamos una variable FLAG a la cual se le pasa el valor X. Antes de imprimir, comprobamos el valor de esta variable para no imprimir si es que ha habido errores.
141
Colores en ABAP
Este programa muestra las posibles combinaciones de colores que pueden generarse en ABAP.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE VARIABLES DATA: I TYPE I, * *=====================================================*
142
COL(15) TYPE C. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM IMPRIMIR. *&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. WRITE:/9 'INTESIFIED ON', 27 'INTENSIFIED OFF', 48 'INVERSE'. SKIP 2. WHILE I < 8. CASE I. WHEN 0. COL = 'COL_BACKGROUND '. WHEN 1. COL = 'COL_HEADING '. WHEN 2. COL = 'COL_NORMAL '. WHEN 3. COL = 'COL_TOTAL '. WHEN 4. COL = 'COL_KEY '. WHEN 5. COL = 'COL_POSITIVE '. WHEN 6. COL = 'COL_NEGATIVE '. WHEN 7. COL = 'COL_GROUP '. ENDCASE. FORMAT INTENSIFIED COLOR = I. WRITE: /(4) I, AT 7 SY-VLINE, COL, SY-VLINE, * *=====================================================*
143
COL INTENSIFIED OFF, SY-VLINE, COL INVERSE. I = I + 1. ENDWHILE. ENDFORM. " IMPRIMIR
Lenguajes y Programas
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE INCLUDES INCLUDE <ICON>. *=====================================================* * DECLARACION DE TYPES * *=====================================================* * *=====================================================*
144
TYPES: BEGIN OF TY_PROGRAMAS, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, NOM_PROG TYPE ZPROGRAMAS-NOM_PROG, 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. *=====================================================* * DECLARACION DE VARIABLES DATA: ICONO TYPE STRING. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM SELECCIONAR_DATOS. PERFORM IMPRIMIR_DATOS. *&----------------------------------------------------* *& Form SELECCIONAR_DATOS * *&----------------------------------------------------* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
145
FORM SELECCIONAR_DATOS. SELECT NOMBRE ENTORNO NOM_PROG INTO TABLE T_PROGRAMAS FROM ( ZLENGUAJES_PROG INNER JOIN ZPROGRAMAS ON ZLENGUAJES_PROG~ID = ZPROGRAMAS~ID ). ENDFORM. " SELECCIONAR_DATOS
*&----------------------------------------------------* *& Form IMPRIMIR_DATOS * *&----------------------------------------------------* FORM IMPRIMIR_DATOS. FORMAT COLOR 5. WRITE:/1 'Lenguaje',15 'Entorno', 25 'Programa', 40 'Icono'. FORMAT COLOR OFF. SKIP 1. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/1 <FS_PROGRAMAS>-NOMBRE, 15 <FS_PROGRAMAS>-ENTORNO, 25 <FS_PROGRAMAS>-NOM_PROG. CASE <FS_PROGRAMAS>-ENTORNO. WHEN 'WEB'. ICONO = ICON_WD_WEB_PROJECT. WHEN 'SCRIPT'. ICONO = ICON_HISTORY. WHEN 'DESKTOP'. ICONO = ICON_FOLDER.
146
Este programa es muy parecido al que hicimos alguna pginas antes, con la particularidad, de estamos mostrando un icono que representa a cada tipo de lenguaje. Para esto, debemos incluir un subprograma llamado <ICON> con la palabra reservada INCLUDE. Gracias a este include, podemos llamar a cualquier icono de la tabla ICON.
LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. WRITE:/1 <FS_PROGRAMAS>-NOMBRE, 15 <FS_PROGRAMAS>-ENTORNO, 25 <FS_PROGRAMAS>-NOM_PROG. CASE <FS_PROGRAMAS>-ENTORNO. WHEN 'WEB'. ICONO = ICON_WD_WEB_PROJECT. WHEN 'SCRIPT'. ICONO = ICON_HISTORY. WHEN 'DESKTOP'. ICONO = ICON_FOLDER. ENDCASE. WRITE: 40 ICONO. ENDLOOP.
Declaramos una variable de tipo STRING llamada ICONO, a la cual vamos a asignarle las constantes de iconos que obtenemos de la tabla ICON (Campo Name). Simplemente utilizando un CASE-
147
ENDCASE sabemos que valores asignar a la variable ICON para luego simplemente imprimirlo.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TYPES TYPES: X_LINES TYPE STRING. *=====================================================* * DECLARACION DE TABLAS INTERNAS * *=====================================================* * *=====================================================*
148
*=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_TABLE> LIKE LINE OF T_TABLE. *=====================================================* * DECLARACION DE VARIABLES DATA: TEXTO(30) TYPE C, AUX_TEXT(30) TYPE C, V_LEN TYPE I, V_LONG TYPE I. *=====================================================* * SELECTION-SCREEN * *=====================================================* SELECTION-SCREEN BEGIN OF BLOCK DEC_TO_BIN WITH FRAME. PARAMETERS: P_TEXTO(20) TYPE C. SELECTION-SCREEN END OF BLOCK DEC_TO_BIN. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM INICIALIZAR. PERFORM FILL_RIGHT_CHARACTERS USING '*' CHANGING TEXTO. PERFORM IMPRIMIR USING TEXTO. * *=====================================================* * *=====================================================* * *=====================================================*
149
PERFORM INICIALIZAR. PERFORM CAPITALIZE_LETTERS CHANGING TEXTO. PERFORM IMPRIMIR USING TEXTO. PERFORM INICIALIZAR. PERFORM SPLIT_LONG_TEXT TABLES T_TABLE USING TEXTO. PERFORM IMPRIMIR_TABLA TABLES T_TABLE. PERFORM INICIALIZAR. PERFORM REVERSE_STRING USING TEXTO. PERFORM IMPRIMIR USING TEXTO. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. TEXTO = P_TEXTO. SKIP 1. ENDFORM. "INICIALIZAR
*&----------------------------------------------------* *& Form IMPRIMIR_TABLA * *&----------------------------------------------------* FORM IMPRIMIR_TABLA TABLES T_TAB. LOOP AT T_TAB ASSIGNING <FS_TABLE>. WRITE:/ <FS_TABLE>.
150
*&----------------------------------------------------* *&----------------------------------------------------* FORM IMPRIMIR USING L_TEXTO. WRITE:/ TEXTO. ENDFORM. "imprimir
*&----------------------------------------------------* *& * Form FILL_RIGHT_CHARACTERS * *&----------------------------------------------------* Llena una cadena con caracteres a la derecha. * *-----------------------------------------------------* FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. V_LEN = STRLEN( L_TEXTO ). DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE. V_LEN = V_LONG - V_LEN. DO V_LEN TIMES. CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. ENDDO. ENDFORM. "FILL_RIGHT_CHARACTERS
151
*&----------------------------------------------------* *& * Form CAPITALIZE_LETTERS * * *&----------------------------------------------------* Capitaliza un texto dado. *-----------------------------------------------------* FORM CAPITALIZE_LETTERS CHANGING L_TEXTO. TRANSLATE L_TEXTO TO LOWER CASE. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. CLEAR L_TEXTO. LOOP AT T_TABLE ASSIGNING <FS_TABLE>. V_LONG = STRLEN( <FS_TABLE> ). V_LONG = V_LONG - 1. AUX_TEXT = <FS_TABLE>+0(1). TRANSLATE AUX_TEXT TO UPPER CASE. CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE. SHIFT L_TEXTO LEFT DELETING LEADING SPACE. ENDLOOP. ENDFORM. "CAPITALIZE_LETTERS
152
*&----------------------------------------------------* *& * * Form SPLIT_LONG_TEXT * * * *&----------------------------------------------------* Corta un texto largo en varios registros de una tabla
*-----------------------------------------------------* FORM SPLIT_LONG_TEXT TABLES T_TAB USING L_TEXTO. CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE DELIMITER TABLES OUT_LINES EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. = T_TAB = L_TEXTO = SPACE
DESCRIBE TABLE T_TAB LINES V_LEN. DELETE T_TAB INDEX V_LEN. ENDFORM. "SPLIT_LONG_TEXT
153
*&----------------------------------------------------* *& * Form REVERSE_STRING * * *&----------------------------------------------------* Invierte una cadena *-----------------------------------------------------* FORM REVERSE_STRING CHANGING L_TEXTO. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING LANG IMPORTING RSTRING EXCEPTIONS TOO_SMALL = 1 OTHERS ENDFORM. = 2. "REVERSE_STRING = L_TEXTO = L_TEXTO = SY-LANGU
En este programa tenemos varios FORMS y cada uno realiza una tarea en particular. Veamos cada uno de ellos.
FORM FILL_RIGHT_CHARACTERS USING L_CHAR CHANGING L_TEXTO. V_LEN = STRLEN( L_TEXTO ). DESCRIBE FIELD L_TEXTO LENGTH V_LONG IN CHARACTER MODE.
154
V_LEN = V_LONG - V_LEN. DO V_LEN TIMES. CONCATENATE L_TEXTO L_CHAR INTO L_TEXTO. ENDDO. ENDFORM. "FILL_RIGHT_CHARACTERS
Utilizamos STRLEN para determinar la longitud total del texto (Incluyendo espacios en blanco). Y luego utilizamos DESCRIBE FIELD LENGTH IN CHARACTER MODE para determinar la longitud pero sin contar los espacios en blanco. En la variable V_LEN, restamos la longitud de V_LONG menos V_LEN, es decir, la longitud con espacios menos la longitud sin espacios. Utizamos un DO para ejecutar un bucle un nmero V_LEN de veces y concatenamos el texto con el carcter de relleno, en este caso el *.
FORM CAPITALIZE_LETTERS CHANGING L_TEXTO. TRANSLATE L_TEXTO TO LOWER CASE. SPLIT L_TEXTO AT SPACE INTO TABLE T_TABLE. CLEAR L_TEXTO. LOOP AT T_TABLE ASSIGNING <FS_TABLE>. V_LONG = STRLEN( <FS_TABLE> ).
155
V_LONG = V_LONG - 1. AUX_TEXT = <FS_TABLE>+0(1). TRANSLATE AUX_TEXT TO UPPER CASE. CONCATENATE AUX_TEXT <FS_TABLE>+1(V_LONG) INTO AUX_TEXT. CONCATENATE L_TEXTO AUX_TEXT INTO L_TEXTO SEPARATED BY SPACE. SHIFT L_TEXTO LEFT DELETING LEADING SPACE. ENDLOOP. ENDFORM. "CAPITALIZE_LETTERS
Primero, convertimos la cadena a Minsculas utilizando el TRANSLATE TO LOWER CASE. Luego con un SPLIT AT SPACE INTO TABLE, enviamos las subcadenas a una tabla interna, para poder modificarlos uno por uno. Con STRLEN determinamos la longitud del Field-Symbol y le restamos uno. Leemos el primer carcter utilizando +0(1) que significa, leer un caracter empezando desde la primera posicin. Utilizando TRANSLATE TO UPPER CASE, convertimos a Maysculas el caracter que hemos ledo. Concatenamos el primer caracter mas los dems caracteres de la cadena. Finalmente concatenamos todos las subcadenas en una cadena ms grande con los letras ya capitalizadas.
156
CALL FUNCTION 'RSDG_WORD_WRAP' EXPORTING TEXTLINE DELIMITER TABLES OUT_LINES EXCEPTIONS OUTPUTLEN_TOO_LARGE = 1 OTHERS = 2. = T_TAB = L_TEXTO = SPACE
DESCRIBE TABLE T_TAB LINES V_LEN. DELETE T_TAB INDEX V_LEN. ENDFORM. "SPLIT_LONG_TEXT
Utilizamos la funcin RSDG_WORD_WRAP para partir una cadena en subcadenas y enviarlas a una tabla. Podramos haber utilizado un SPLIT INTO TABLE, pero quera que vieran como se utilizan los mdulos de funciones. Al final, utilizando un DESCRIBE TABLE LINES para poder determinar cuantas lneas tiene nuestra tabla interna. El mdulo de funciones que utilizamos tiende a tomar los espacios en blanco y agregarlos como longitud total de la cadena, es por eso que sabiendo cuantas lneas tienen la tabla interna, podemos eliminar la ltima sin tener problemas.
FORM REVERSE_STRING CHANGING L_TEXTO. CALL FUNCTION 'STRING_REVERSE' EXPORTING STRING = L_TEXTO
157
= SY-LANGU = L_TEXTO
158
SapScript
Introduccin
Uno de los puntos fuertes que tiene el ABAP, es la posibilidad de crear formularios, que pueden ser utilizados por ejemplo, para Certificados de Trabajo, Notificaciones de Empresa, Facturas, etc. Su creacin no es complicada y permite hacer varias cosas interesantes. Como por ejemplo, incluir logos o imprimir cdigos de barras, aunque lo ltimo depende ms que nada de la impresora o de software adicional para poder mostrarlos correctamente.
Creando un formulario
Para poder crear formularios, debemos ingresar a la transaccin SE71 (Form Painter).
159
En el campo formulario, ingresamos el nombre de nuestro formulario y en el campo idioma, el idioma en el cual queremos crearlo (Bastante simple no?). En realidad, el idioma se utiliza para poder crear de una manera ms sencilla las traducciones, puesto que cuando uno ingresa a NetWeaver, puede hacerlo con muchos idiomas predefinidos (Bueno, no esta versin, puesto que solamente permite Alemn e Ingls...La versin completa del NetWeaver incluye entre muchos otros, Espaol, Francs, Italiano...). Presionamos el botn Create (Crear) crear nuestro formulario. para poder
160
En esta ventana, deberemos ingresar un texto que describa brevemente al formulario. Luego de esto, deberemos ingresar a la seccin de Basic Settings (Parametrizaciones Bsicas) con el siguiente botn .
161
En esta ventana, se nos exige especificar una Pgina Inicial y un Prrafo por defecto. Como este formulario es nuevo, ninguno de estos existe, por lo cual deberemos crearlos. 1.- Crear una pgina inicial Ingresamos a la opcin Pages (Pginas), presionando el siguiente botn .
Como vemos, no existe ninguna pgina. Para poder crearla, necesitamos crear un nuevo elemento. Esto podemos hacerlo de 3
162
formas. Con un clic derecho, con el men de la transaccin o presionando SHIFT + F6.
Men de transaccin Cuando creamos un nuevo elemento, el sistema nos mostrar la siguiente ventana:
163
En Page (Pgina) ingresaremos el nombre de la pgina que queremos crear y en Description (Description), una descripcin de la pgina. Por convencin, simpre la pgina principal ser llamada MAIN. Luego de haber creado el elemento, podremos verlo como se muestra a continuacin.
2.- Crear una ventana en una pgina Despus de haber creado nuestra pgina, deberemos asignarle una ventana, que es el espacio en el cual vamos a trabajar para poder crear nuestros formularios. Una pgina puede tener muchas ventanas. Y un formulario puede tener muchas pginas. Para poder crear una ventana, deberemos hacer clic en el botn Page Windows (Ventanas de Pgina) .
164
Y seguir un procedimiento similar al de la creacin de la pgina. Es decir, deberemos de crear un nuevo elemento. Cuando creamos el nuevo elemento, se nos muestra la siguiente ventana.
En esta ventana, se nos muestra una ventana por defecto, creada cuando creamos la pgina. Si queremos crear ventanas adicionales,
165
Para poder elegir la ventana, simplemente deberemos de hacer un doble clic sobre ella.
Por cada Ventana Pgina que creemos, 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, tenemos disponibles los siguientes sistemas de medicin. 166
3.- Crear prrafo por defecto Para crear un nuevo prrafo, deberemos hacer clic en el botn Paragraph Formats (Formatos de Prrafo) Se nos mostrar la siguiente ventana: .
Aqu deberemos asignarle un nombre al nuevo prrafo (Por convencin utilizamos ST), as como el tipo de letra (Con el botn Font ), ), los tabuladores (Con el botn Tabs su asignacin (Con el botn Outline
), etc.
167
Una vez que hemos creado la pgina y el prrafo por defecto, deberemos regresar a la configuracin de cabecera para poder finalizar con las parametrizaciones bsicas. Para esto, simplemente hacemos un clic en el botn Header (Cabecera) F5. Y luego en el botn o presionamos bsicas
parametrizaciones
168
Una vez que hemos terminado, debemos grabar el formulario y activarlo mediante el men.
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS,ITCPO,TOA_DARA,ITCPP. * *=====================================================*
169
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_ZPROGRAMAS. *=====================================================* * DECLARACION DE VARIABLES DATA: V_FORM(14) TYPE C, V_SCRIPT. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM INICIALIZAR. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
170
*=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM ABRIR_SAPSCRIPT. *&----------------------------------------------------* *& Form INICIALIZAR * *&----------------------------------------------------* FORM INICIALIZAR. V_FORM = 'ZDUMMY_FORM'. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG. ENDFORM. "INICIALIZAR * *=====================================================*
*&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SAPSCRIPT. ITCPO-TDIMMED = '*'. ITCPO-TDDELETE = '*'. ITCPO-TDLIFETIME = '7'. ITCPO-TDPREVIEW = 'X'. IF V_SCRIPT EQ SPACE. CALL FUNCTION 'OPEN_FORM' EXPORTING
171
FORM LANGUAGE OPTIONS DEVICE DIALOG EXCEPTIONS CANCELED IF SY-SUBRC NE 0. EXIT. ENDIF. V_SCRIPT = 'X'. ENDIF.
ARCHIVE_INDEX = TOA_DARA
CALL FUNCTION 'START_FORM' EXPORTING FORM = V_FORM LANGUAGE = 'S'. LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'MAIN' WINDOW EXCEPTIONS OTHERS ENDLOOP. CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. = 01. = 'MAIN'
172
TABLES: ZPROGRAMAS,ITCPO,TOA_DARA,ITCPP.
Las tablas ITCPO, TOA_DARA y ITCPP son necesarias para poder ejecutar el SAPScript.
La variable V_FORM contendr el nombre del formulario, mientras que la variable V_SCRIPT nos sirve para determinar si el formulario est activo o no.
Parmetro impresin, salida inmediata. Parmetro impresin, borrar tras salida. Parmetro impresin, tiempo de permanencia en SPOOL.
173
Visualizacin de impresin.
CALL FUNCTION 'OPEN_FORM' EXPORTING FORM LANGUAGE OPTIONS DEVICE DIALOG EXCEPTIONS CANCELED IF SY-SUBRC NE 0. EXIT. ENDIF. V_SCRIPT = 'X'. = 01. = V_FORM = 'S' = ITCPO = 'PRINTER' = 'X'
IF V_SCRIPT EQ SPACE.
ARCHIVE_INDEX = TOA_DARA
ENDIF.
Si la variable V_SCRIPT est vaca, entonces debemos abrir el formulario, para OPEN_FORM. esto utilizamos el mdulo de funciones
174
LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW EXCEPTIONS OTHERS ENDLOOP. = 01. = 'MAIN'
Hacemos un LOOP a la tabla interna T_ZPROGRAMAS y asignamos los valores al Field-Symbol <FS_PROGRAMAS>. Por cada vuelta del LOOP, llamamos al mdulo de funciones WRITE_FORM que lo que hace es llamar a la ventana de nuestro formulario.
CALL FUNCTION 'END_FORM' IMPORTING RESULT = ITCPP. IF V_SCRIPT NE SPACE. CALL FUNCTION 'CLOSE_FORM'. ENDIF.
Con el mdulo de funciones END_FORM indicamos que hemos terminado de utilizar la ventana. Si la variable V_SCRIPT no est vaca, cerramos el formulario con el mdulo de funciones CLOSE_FORM.
175
Una vez creado el programa, podemos regresar a nuestro formulario para poder comenzar a llenar los datos que queremos mostrar cuando sea ejecutado.
Diseando el formulario
Adems de la forma que ya vimos para crear nuestro formulario, contamos con un editor grfico. Para poder acceder, deberemos ingresar a la transaccin SE71 (Form Painter). Debemos ingresar al men Settings (Opciones) y presionar Form Painter.
Simplemente, debemos marcar el check Graphical Form Painter (Form Painter grfico).
176
En este editor grfico, podemos especificar el tamao y la disposicin de las distintas ventanas que creemos en nuestro formulario. Para volver al modo de edicin por defecto, simplemente debemos desmarcar el checkbox de Form Painter grfico. Para poder asignar el cdigo a la ventana, deberemos presionar el botn Text (Texto) . 177
En esta ventana, podremos escribir el cdigo para llamar a los campos que definimos en nuestro programa (Es decir, a los campos de la tabla interna) y mostrarlos al momento de imprimir el formulario.
Como podemos ver, podemos llamar al tipo de prrafo por defecto de dos maneras, dejando el men por defecto, o llamandolo explictamente como ST Prrafo por defecto. En la parte de cdigo, veremos que hemos escrito texto y el nombre de los campos del field-symbol dentro de ampersands (&). Si los
178
ampersand, no podramos llamar a las variables de nuestro programa dentro del formulario. Supongamos que queremos que los textos se muestren en negrita y los valores como un texto normal. Primero que nada, debemos grabar nuestro cdigo y retroceder con el botn BACK (Retroceder) o presionar F3.
Ahora, de vuelta en nuestra ventana, haremos lo siguiente. Seleccionamos el texto que queremos en negrita, y seleccionamos el formato de caracter que creamos.
179
Para terminar, vamos a crear una caja para que se muestre el nombre del programa. Para esto, debemos cambiar de editor, puesto que debemos crear la caja utilizando cdigo.
Y de paso eliminamos cualquier cdigo adicional que haya agreagado el SAPScript. (Yo recomiendo siempre utilizar este editor).
180
Creamos una caja que empieza en la posicin 0, que tenga 50 milimetros de ancho y 5 de alto, y que el borde sea de 10 TW. Se habrn dado cuenta, de que adems agregamos la lnea
/E
ITEM
Puesto que ITEM va a ser nuestro ELEMENTO dentro del ventana. Una ventana se puede llamar una sola vez, pero un elemento, varias veces. Grabamos, activamos y ejecutamos nuestro programa.
Al momento de ejecutar el programa, se nos muestra una ventana de impresin, puesto que al tratarse de un formulario, debemos imprimirlo para poder visualizarlo. Elegimos LP01 como impresora por defecto y presionamos Print Preview (Vista previa de
181
impresin). Puesto que no queremos imprimirlo, sino simplemente comprobar que est bien hecho el formulario.
Los datos son correctos, pero los textos estn muy juntos los unos de los otros, adems la caja de texto simpre est en el mismo lugar, veamos como resolvemos esto.
En el editor, agregamos YPOS &POS& MM, es decir indicamos cual va a ser la posicin Y de la caja. En este caso, va a ser un valor variales indicado por &POS&.
182
Adems, agregamos una lnea en blanco. Para que esto funcione correctamente, debemo tambin agregar algunas cosas en el programa.
LOOP AT T_ZPROGRAMAS ASSIGNING <FS_PROGRAMAS>. CALL FUNCTION 'WRITE_FORM' EXPORTING ELEMENT = 'ITEM' WINDOW EXCEPTIONS OTHERS ENDLOOP. = 01. POS = POS + 13. = 'MAIN'
En cada iteracin del LOOP, luego de haber impreso el contenido del elemento, aumentamos el valor de la variable POS en 13. Ahora, ya podemos imprimir nuevamente el formulario.
183
Para terminar, podramos crear una tabulacin, con lo cual el texto ID Programa quedara ms centrado en la caja. Nos vamos a Paragraph Formats .
184
Creamos una tabulacin de 5 MM con alineacin a la izquierda. Regresamos al Layout y cambiamos el formato del editor. Para agregar un tabulador, escribimos ,, antes del texto.
185
Debugger en SAPScript
Hay que veces que necesitamos hacer un Debug a un SAPScript. Esto es bastante sencillo, aunque no mucha gente lo sepa, puesto que no es una opcin que est muy a la vista, y claro...No es de las mejores herramientas de SAP. Para activar el Debugger, ingresamos al transaccin SE71 (Form Painter). Y elegir Utilities Activate Debugger (Utilidades Activar Debugger).
186
Por lo general se utiliza el botn Single Step (Paso sencillo), puesto que nos permite recorrer el formulario lnea por lnea (En el caso de los textos caracter por caracter). Con esto, podemos ver cual es el contenido de las variables.
187
SmartForms
Introduccin
Los SmartForms, son la nueva generacin de formularios (Ok...No tan nuevas si consideramos a los Adobe Forms, que no se incluyen en este libro) que reemplazan a los para algunos obsoletos formularios SAPScript. En realidad es cuestin de gustos...Yo siempre he sido un fantico acerrimo del SAPScript.
Creando un estilo
Para crear un estilo debemos ingresar a la transaccin
188
En esta ventana, vamos a crear nuestro prrafo por defecto, tal como lo hicimos en el SAPScript. Debemos crear un nuevo nodo en la opcin Paragraph Format (Formato de Prrafo).
189
Y llenamos su descripcin.
Tipo de Letra, tamao e inclusive color (Claro...para impresoras a colores, que seamos realistas, es lo que menos abunda en las empresas).
190
Cuando hemos terminado, hacemos doble clic en Header Data (Datos de Cabecera).
191
Creando un Formulario
Creamos nuestro primer SmartForm llamado
ZPRIMER_SMARTFORM.
En la pestaa Output Options (Opciones de Salida), debemos asignar el estilo que creamos.
192
Al igual que en SAPScript, necesitamos una pgina y una ventana. Como vemos %PAGE1 est creada por defecto, as que podemos dejarla as, o asignarle un nuevo nombre. Lo mismo ocurre con la ventana MAIN.
Para poder escribir en esta ventana, debemos crear un texto de la siguiente manera. Clic derecho en MAIN, Create Text (Crear Texto).
193
194
Para poder utilizar las variables dentro del SmartForms, debemos definir algunas variables globales, para esto nos vamos a Form Interface (Interface de Formulario).
Ahora nos vamos a Global Definitions (Definiciones Globales) y luego a la pestaa Global Data (Datos Globales). Aqu creamos una estructura intermedia que recoge los datos del SmartForms y los almacena para poder mostrarlos en el formulario.
195
Debemos crear un LOOP para poder asignar los valores de la tabla de parmetro a la tabla intermedia.
Una vez creado, debemos mover nuestro texto, dentro del LOOP.
196
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. * *=====================================================* * *=====================================================*
197
*=====================================================* * DECLARACION DE VARIABLES DATA: MODULO_FUNCION TYPE RS38L_FNAM. *=====================================================* * SELECTION-SCREEN SELECTION-SCREEN BEGIN OF BLOCK APP WITH FRAME. SELECT-OPTIONS: SID_PROG FOR ZPROGRAMAS-ID_PROG. SELECTION-SCREEN END OF BLOCK APP. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM INICIALIZAR. *=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM ABRIR_SMARTFORMS. * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
198
SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID_PROG IN SID_PROG. ENDFORM. "INICIALIZAR
*&----------------------------------------------------* *& Form ABRIR_SAPSCRIPT * *&----------------------------------------------------* FORM ABRIR_SMARTFORMS. CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME IMPORTING FM_NAME EXCEPTIONS NO_FORM OTHERS = 1 = 3. NO_FUNCTION_MODULE = 2 = MODULO_FUNCION = 'ZPRIMER_SMARTFORM'
199
Revisemos el programa.
DATA: MODULO_FUNCION TYPE RS38L_FNAM.
Declaramos una variable llamada MODULO_FUNCION del tipo RS38L_FNAM. Porque hacemos esto? Muy simple, los SmartForms se generan como mdulos de funciones, por lo tanto, necesitamos una variable que tenga el mismo tipo que los Mdulos de Funciones.
CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME' EXPORTING FORMNAME IMPORTING FM_NAME EXCEPTIONS NO_FORM OTHERS = 1 = 3. NO_FUNCTION_MODULE = 2 = MODULO_FUNCION = 'ZPRIMER_SMARTFORM'
200
Utilizamos
el
mdulo
de
funciones
SSF_FUNCTION_MODULE_NAME para poder obtener el nombre del mdulo de funciones que gener el SmartForms.
CALL FUNCTION MODULO_FUNCION TABLES T_PROGRAMAS EXCEPTIONS FORMATTING_ERROR = 1 INTERNAL_ERROR SEND_ERROR USER_CANCELED OTHERS = 2 = 3 = 4 = 5. = T_ZPROGRAMAS
Con la variable MODULO_FUNCION, hacemos una llamada dinmica al SmartForms y pasamos los parmetros necesarios, en este caso la tabla interna T_ZPROGRAMAS. Grabamos, activamos y ejecutamos el programa.
Ejecutando el formulario
Al igual que en el SAPScript, se nos mostrar una pantalla de parmetros de impresin.
201
Tenemos nuestra lista, impresa en color azul. Si les parece que est un poco abajo, es cuestin simplemente de ajustar las propiedades del texto.
202
203
En la pestaa DATA (Datos) debemos hacer lo mismo que habamos hecho en el LOOP, asignar la tabla de parmetro a nuestra tabla intermedia.
En la pestaa Table (Tabla), debemos hacer clic en el botn Details (Detalles) , para poder asignar un nombre de
204
Para crear la cabecera de nuestra tabla, nos posicionamos en Header y con un clic derecho escogemos Create (Crear) (Lnea de Tabla). Table Line
205
Como veremos, solamente tenemos un %CELL1 es decir, una sola celda, pero nosotros necesitamos dos, as que vamos al nodo principal %TABLE1 a la pestaa Table y dentro del Formulario grfico, dibujamos una lnea vertical (Con esto creamos automticamente un %CELL2).
Como tenemos reservados los espacios para dos campos, debemos agregar en cada uno un Texto para poder mostrar el ttulo de cada campo.
206
Seguimos el mismo procedimiento para Main Area (Area Principal), es decir, creamos una Lnea 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.
207
Si queremos que se note que hemos utilizado una tabla, hacemos lo siguiente. En el nodo principal de la tabla, hacemos clic sobre el botn Draw Lines and Columns (Dibujar lneas y columnas) deshabilitarlo. Seleccionamos los campos de nuestra lnea de tabla (Utilizando la tecla Control). , para
208
El botn Display Framed Patterns (Mostrar patrones con marco) . Y seleccionamos el tipo que se muestra en la figura.
209
210
Screen Painter
Para poder crear Dynpros o pantallas en ABAP, deberemos ingresar a la transaccin SE51 (Screen Painter).
211
En el campo Program (Programa) ingresaremos el nombre del programa en el cual se va a utilizar el dynpro, y en el campos Screen Number (Nmero de Pantalla), establecemos el nmero de la pantalla, ya que podemos tener muchas pantallas relacionadas entre si. O inclusive, llamar a pantallas distintas dependiendo de una condicin dada. Como en el caso de los programas, deberemos hacer clic en el botn Create (Crear) vamos a crear un programa nuevo. . Es importante que el programa
Aqu deberemos ingresar una descripcin breve, que explique para que va a ser utilizada la pantalla. 212
En Screen Type (Tipo pantalla), debemos especificar que tipo de Dynpro queremos crear, por lo general utilizamos Normal. En el caso de Next Screen (Siguiente pantalla), lo llenaremos solamente si es que luego de esta pantalla vamos a llamar a otra. En este caso, lo dejamos con el valor por defecto. Los dems parmetros podemos dejarlos como estn. Para poder comenzar a disear nuestra pantalla, debemos hacer clic en el botn Layout (Disposicin) .
213
Cursor que sirve para seleccionar y mover los controles dentro del dynpro. Campo de texto, sirve para crear labels o etiquetas descriptivas. Campo de Entrada/Salida, nos sirve tanto para recoger como para obtener datos. Casilla de Seleccin o Checkbox. Botn de Seleccin o RadioButton. Pulsador o Botn. Control de fichas o Control de Tabuladores. Wizard de control de Fichas o Control de tabuladores. Permite crear este control mediante un ayudante paso a paso. Box. Permite crear un contenedor para los controles. rea SubScreen. Permite colocar un Dynpro de tipo SubScreen dentro de otro Dynpro de tipo Normal. Table control. Llamado tambin Tabla o Grilla. Wizard de Table Control o Grilla. Permite crear este control mediante un ayudante paso a paso.
214
Custom Control o Control Personalizado. Nos permite crear elementos en tiempos de ejecucin. Muy utilizados para programacin en ABAP Objects. Icono Status. Permite establecer el status de una pantalla, es decir, si la ejecucin de la pantalla fue exitosa o errnea. Para poder crear cualquiera de estos controles, bastar con seleccionarlos y arrstrarlos hacia el espacio de nuestro dynpro.
215
Luego, vamos a crear un control Input/Output Field (Campo de Entrada/Salida), al cual vamos a asociarlo con un campo de la base de datos. Por lo tanto utilizaremos el nombre ZPROGRAMAS-ID.
Una vez ingresado el nombre, se nos mostrar el siguiente mensaje (Esto es porque estamos utilizando el nombre de una tabla y un campo, por lo cual, obtenemos sus caractersticas y existe una relacin directa con la Base de Datos).
216
Deberemos hacer clic en Yes (S) para que nuestra caja de texto tome la referencia del campo ID de la tabla ZPROGRAMAS. Para poder acceder a las propiedades de este control, simplemente debemos hacer un doble clic.
217
218
Ahora, debemos crear nuestra tabla con el control Table Control . Nuestra tabla, se llamar TABLA.
Para poder crear los campos de nuestra tabla, deberemos utilizar un control Text Field y otro control Input/Output Field, para cada campo que deseemos mostrar.
219
Primero debemos crear el control Input/Output Field y luego el Text Field. Ambos referenciando a un campo de una tabla. En este caso, el primero T_ZPROGRAMAS-ID_PROG y el segundo T_ZPROGRAMAS-NOM_PROG.
En este caso, vamos a asociar los campos de nuestra tabla a una tabla interna, que vamos a crear en nuestro programa, llamada T_ZPROGRAMAS. Esta tabla vamos a definirla en el programa ZDUMMY_PRIMER_PROGRAMA que en este caso, es el programa control para el Dynpro.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS. * *=====================================================*
Luego de haber creado nuestros controles en el Dynpro, debemos crear la lgica de proceso para nuestra pantalla. Para esto, debemos hacer clic en el botn Flow Logic (Flujo lgico) . 220
Debemos descomentar ambos mdulos y hacer doble clic en cada uno de ellos para que se autogeneren en el cdigo fuente de nuestro programa de control y as poder utilizarlos. Para poder llenar la tabla con los datos obtenidos en base al filtro, deberemos incluir el siguiente cdigo marcado en rojo.
Con esto, simplemente leemos el contenido de la tabla interna T_ZPROGRAMAS y lo asignamos a cada campo de nuestra tabla. Dentro del MODULE STATUS_0100, debemos ingresar el siguiente cdigo (Para esto, simplemente hacemos doble clic en el texto STATUS_0100). 221
En esta ventana, nos avisan que el mdulo STATUS_0100 no existe. Por lo tanto, debemos crearlo aceptando el mensaje.
Cuando el NetWeaver va a crear un nuevo mdulo o funcin, nos pregunta si queremos crearlo en el programa fuente, o queremos crear un INCLUDE (Es decir, un programa adicional que ser llamado por el programa principal). En este caso, vamos a crearlo en el programa principal.
222
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. DATA: LINEAS TYPE I, ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. TABLA-LINES = LINEAS. * * SET PF-STATUS 'xxxxxxxx'. SET TITLEBAR 'xxx'. " STATUS_0100 OUTPUT
ENDMODULE.
Se darn cuenta de que los SET estn comentados...Eso es porque vamos a verlos ms adelante. Ahora, podemos agregar el cdigo necesario a nuestro programa.
223
REPORT ZDUMMY_PRIMER_PROGRAMA NO STANDARD PAGE HEADING. *=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_ZPROGRAMAS TYPE STANDARD TABLE OF ZPROGRAMAS WITH HEADER LINE. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. CALL SCREEN '100'. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. DATA: LINEAS TYPE I, ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. * *=====================================================* * *=====================================================* * *=====================================================*
224
IF ID NE SPACE. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. TABLA-LINES = LINEAS. ENDIF. * * SET PF-STATUS 'xxxxxxxx'. SET TITLEBAR 'xxx'. " STATUS_0100 OUTPUT
ENDMODULE.
*&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. ENDMODULE. " USER_COMMAND_0100 INPUT
Revisemos el cdigo.
START-OF-SELECTION. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. CALL SCREEN '100'.
Debemos crear un control llamado TABLA de tipo TABLEVIEW (Vista de Tabla) utilizando la pantalla 100. En otras palabras,
225
debemos declarar por cdigo, que hemos creado una tabla en la pantalla 100. Finalmente, llamamos a la pantalla 100.
MODULE STATUS_0100 OUTPUT. DATA: LINEAS TYPE I, ID TYPE ZPROGRAMAS-ID. ID = ZPROGRAMAS-ID. IF ID NE SPACE. SELECT * INTO TABLE T_ZPROGRAMAS FROM ZPROGRAMAS WHERE ID EQ ID. DESCRIBE TABLE T_ZPROGRAMAS LINES LINEAS. TABLA-LINES = LINEAS. ENDIF. * * SET PF-STATUS 'xxxxxxxx'. SET TITLEBAR 'xxx'. " STATUS_0100 OUTPUT
ENDMODULE.
de tipo
226
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. Si la variable ID no est vaca (Es decir, hemos ingresado un valor en la caja de texto), entonces podemos continuar. Seleccionamos todos los campos de la tabla ZPROGRAMAS siempre y cuando, el ID sea igual a nuestra variable ID. Obtenemos la cantidad de lneas que hay en la tabla interna, utilizando el comando DESCRIBE TABLE. Finalmente asignamos la variable LINEAS (Que contiene la cantidad de lneas de la tabla interna) al campo LINES de nuestra tabla TABLA, es decir, le decimos cuantas lneas se deberan de mostrar en la tabla. Para poder ejecutar el programa, debemos activar tanto el Dynpro como el programa.
227
Si se fijan bien, se darn cuenta de que todos los botones en la barra de transacciones estn deshabilitados.
Esto se debe a que no hemos asociado un men a nuestra pantalla. Por lo tanto debemos crear uno en la transaccin SE41.
228
Menu Painter
Lo primero que debemos hacer, es crear un Status, que en este caso, va a ser el 100. Para ello, como siempre, deberemos hacer clic en el botn Create (Crear) .
En la ventana que nos muestra el NetWeaver, debemos ingresar un texto breve o descripcin que nos indique para que se utilizar este men. En cuanto al Status Type (Tipo de Status), dejemos el que viene por defecto, es decir Online Status (Status en lnea).
229
230
Aqu debemos establecer que botones queremos habilitar y cuales son sus nombre de funcin.
Ahora, debemos grabar y activar. Con esto, nuestro men est listo para utilizarse. Para poder agregarlo a nuestro programa, simplemente deberemos incluir la siguiente lnea (O ms bien, descomentarla).
231
El SET PF-STATUS le dice a nuestro Dynpro, que queremos utilizar un men creado por nosotros, y 100 es el nmero de dicho men. Con esto parecera ser suficiente...Pero no...An debemos asignar las funciones que va a cumplir cada uno de los botones de nuestro men, para ello, debemos incluir el siguiente cdigo.
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
En este caso, los tres botones hacen lo mismo, as que no hay mucho problema. La variable del sistema SY-UCOMM, determina que valor tiene el botn que ha sido presionado. Aunque en este caso no es necesario, cuando tengamos ms botones, deberamos incluir el OK_CODE dentro de nuestro Dynpro, as que vamos a la transaccin SE51.
232
233
Se darn cuenta de que el ttulo de nuestro programa es SAP...Y este es un ttulo por defecto, as que vamos a crear uno ms interesante. Primero, debemos descomentar la siguiente lnea.
234
Aceptamos y continuamos.
Agregamos un ttulo, aceptamos...Y ahora viene una pequea crtica a SAP...Si queremos activar el ttulo, debemos hacer una de dos cosas...Ingresar a la SE41 y activar o sino, recompilar el cdigo fuente y activarlos juntos. Para m, el ttulo debera activarse cuando aceptamos esta ventana...en fn...
235
Como podemos ver, los atributos del pulsador poseen dos campos adicionales, que son Icon Name (Nombre de Icono) y Tooltip (Informacin adicional). Para seleccionar el icono, simplemente hacemos clic en el botn Choose Icon (Escoger Icono) .
236
Esta ventana nos muestra todos los iconos disponibles. El Tooltip, no es ms que el mensaje que aparece cuando situamos el mouse sobre el componente. El valor del FctCode (Function Code Cdigo de Funcin), es sumamente importante, puesto que nos va a ayudar a activar el evento relacionado al botn PROCESAR.
Como FctCode vamos a utilizar el mismo nombre del botn. Dentro del programa, hacemos unos pequeos 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 accin cuando se presione el botn. La accin 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 darn cuenta de que el cdigo es el mismo que estaba dentro del MODULE STATUS_0100 OUTPUT. Con lo cual el mdulo quedara 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 botn para que se llene la tabla).
239
Si han sido curiosos u observadores, se habrn dado cuenta de que los campos de la tabla pueden modificarse, por lo tanto podramos cambiar los valores que obtenemos de la tabla. Corregir esto es muy sencillo, simplemente regresamos a la transaccin 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 estn protegidos de malas acciones.
240
Lo que hace el POV (Process on value-request / Proceso en requerimiento de valor) es llamar a un mdulo cuando presionamos F4 en un campo. Gracias a esto, podemos definir nosotros mismos la ayuda de bsqueda.
241
Lo primero que debemos hacer es crear el mdulo, que como ya sabemos se hace haciendo doble clic sobre el nombre del mdulo. 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 ms que un modo genrico 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 Adems, debemos crear algunas variables necesarias para la funcin 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 funcin que crea los MatchCodes dinmicos.
Con
esto, el
ya
estamos ID
listos ya
para un
programar
nuestro Muy
simple...Nuestro MatchCode va a mostrar solamente el ID y ya no el ID y el Nombre...Claro debera de ser al revs, pero el ejemplo sirve para ilustrar lo que podemos hacer. Antes de continuar, como vamos a llamar a un Mdulo de Funciones, podemos utilizar un poco de ayuda. Presionamos el botn Pattern (Patrn) pantalla muy interesante. Esta pantalla completa el cdigo por nosotros utilizando una plantilla, en donde los parmetros no obligatorios estn comentados. Ingresamos F4IF_INT_TABLE_VALUE_REQUEST en el campo CALL FUNCION (Llamar funcin) y aceptamos. y veremos una
243
MODULE MATCH_CODE_ID INPUT. SELECT ID INTO TABLE T_MATCHCODE_ID FROM ZPROGRAMAS. DYNPROFIELD = 'ZPROGRAMAS-ID'. DYNNUM = '100'. PROGNAME = SY-REPID. CLEAR RETURN_TAB. REFRESH RETURN_TAB. CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' EXPORTING RETFIELD DYNPPROG = 'ID' = PROGNAME
244
245
El campo DYNPROFIELD almacena a que campo se va a aplicar el MatchCode, el campo DYNNUM almacena cual es el nmero del Dynpro y el campo PROGNAME almanacena cual es el nombre del programa.
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. = T_MATCHCODE_ID = RETURN_TAB = 'ID' = PROGNAME = DYNNUM = DYNPROFIELD = 'S'
246
El mdulo de funciones recibe las variables con la informacin del Dynpro y la tabla conteniendo los valores de los IDs. Nos muestra una ventana con los valores disponibles y el que hayamos elegido es guardado en la tabla RETURN_TAB. Si hemos escogido algn valor, entonces lo mostramos en el campo ZPROGRAMAS-ID.
247
Debemos marcar el check w/SelColumn (con Seleccin de columna) y asignarle un nombre, que en este caso, va a ser FILA. La variable FILA nos a indicar cuando hayamos seleccionado un registro. Adems, vamos a agregar un botn llamado ELIMINAR.
248
Como vemos, el botn tiene un FctCode llamado ELIMINA y un Icono llamado ICON_DELETE, adems de un Tooltip con el texto Eliminar.
249
Tenemos que ingresar al Flow Logic para crear un mdulo asociado el botn ELIMINAR.
PROCESS AFTER INPUT. MODULE USER_COMMAND_0100. LOOP AT T_ZPROGRAMAS. MODULE ELIMINAR_FILA. ENDLOOP.
IF SY-UCOMM EQ 'ELIMINA'. IF FILA EQ 'X'. DELETE T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. ENDIF. ENDIF. ENDMODULE. " ELIMINAR_FILA INPUT
Declaramos una variable llamada FILA de tipo C, recordemos que esta variable va a ser equivalente a la del Dynpro. Si hemos presionado el botn ELIMINAR, entonces continuamos, y automticamente, el sistema va a recorrer todas las filas de nuestra tabla hasta encontrar la que est seleccionada, en ese momento el
250
valor de FILA va a ser X. Borramos este valor de nuestra tabla interna y como consecuencia, se borra tambin de la tabla. Claro, esto no lo borra de la Base de Datos, aunque sera bastante sencillo hacer que lo haga, simplemente necesitaramos seleccionar la llave primaria de la tabla y hacer un DELETE TABLE.
251
MODULE ACTUALIZA_TABLA INPUT. MODIFY T_ZPROGRAMAS INDEX TABLA-CURRENT_LINE. ENDMODULE. " ACTUALIZA_TABLA INPUT
Con esto, modificaremos el contenido del registro del table control que hemos modificado. La variable CURRENT_LINE nos indica que registro es el que estamos modificando.
Ahora, lo que vamos a hacer es agregar un botn que nos permita cambiar entre el modo visualizacin y el modo modificacin en el programa.
252
En este caso, podemos definir un Static Text (Texto Esttico) o un Dynamic Text (Texto Dinmico). Empecemos creando uno esttico.
253
En esta ventana, definimos el cdigo de funcin asociado al pulsador, el texto asociado a la funcin, el icono asociado y finalmente el texto informativo.
254
Debemos asignar una tecla de funcin a cada pulsador que creemos. En este caso, vamos a elegir el F2.
Finalmente, deberemos hacer un clic al costado del Icono para una ltima ventana de propiedades.
En esta nueva ventana, debemos escoger el texto que acompaar al icono que hemos seleccionado. En el caso de nos especificar ningn texto, el sistema tomar el texto por defecto del pulsador. Cuando grabamos y activamos, queda as.
255
Le toca ahora al pulsador con texto dinmico, veamos como crearlo. Debemos seguir los pasos anteriores hasta que lleguemos a esta pantalla (Claro, debemos escoger Dynamic Text esta vez).
En este caso, Field name (Nombre Campo) es una variable que deberemos crear en nuestro programa. Asignaremos cualquier tecla de funcin y continuaremos. Finalmente tendremos esto.
De vuelta en el programa, tendremos que crear una variable y asignarle valores para nuestro texto dinmico.
DATA: DYNPROFIELD TYPE HELP_INFO-DYNPROFLD, PROGNAME TYPE SY-REPID, DYNNUM TYPE SY-DYNNR, TEXTO_DINAMICO TYPE SMP_DYNTXT.
256
START-OF-SELECTION. TEXTO_DINAMICO = 'Este es un texto dinmico'. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. CALL SCREEN '100'.
En el Screen Painter debemos cambiar los atributos de los componentes de la tabla. Nuevamente deben de estar como campos de salida. Esto es para que los componentes de la tabla estn protegidos por defecto. En el programa, 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.
START-OF-SELECTION. TEXTO_DINAMICO = 'Este es un texto dinmico'. CONTROLS TABLA TYPE TABLEVIEW USING SCREEN '100'. DATA: COLS LIKE LINE OF TABLA-COLS. CALL SCREEN '100'.
Declaramos la tabla COLS como una lnea de la tabla TABLACOLS, esto es porque TABLA-COLS es una Deep Structure 257
(Estructura profunda), es decir, es una tabla dentro de otra tabla. Adems, solo necesitamos una cabecera y no toda la tabla. Agregamos el evento generado por el pulsador CHANGESTAT.
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. WHEN 'CHANGESTAT'. PERFORM CAMBIAR_ESTADO. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
FORM CAMBIAR_ESTADO. LOOP AT TABLA-COLS INTO COLS. IF COLS-SCREEN-INPUT = '0'. COLS-SCREEN-INPUT = '1'. TEXTO_DINAMICO = 'Modificar'. ELSEIF COLS-SCREEN-INPUT = '1'.
258
COLS-SCREEN-INPUT = '0'. TEXTO_DINAMICO = 'Visualizar'. ENDIF. MODIFY TABLA-COLS FROM COLS. ENDLOOP. ENDFORM. " CAMBIAR_ESTADO
Hacemos un LOOP a la tabla TABLA-COLS y guardamos cada lnea o registro dentro de nuestra tabla COLS. Verificamos el estado del campo INPUT, si es cero, entonces estamos visualizando y si es uno estamos modificando. Cambiamos los estados, los textos del botn dinmico y finalmente modificamos la tabla para que los cambios queden registrados.
259
260
Algunas veces necesitamos incluir pantallas completas de otras pantallas, sobre todo cuando tenemos que utilizar Tabs o Pestaas. Vamos a olvidarnos de nuestro programa anterior, y vamos a crear uno nuevo utilizando pestaas y un SubScreen. Vamos a crear una nueva pantalla y un nuevo programa. Y por supuesto nuestro TabStrip Control llamado TAB.
Asignamos un nombre a cada TAB (Pestaa) del TabStrip Control. Es muy importante que definamos el Tipo de Funcin que este caso es P (Local Gui Function Funcin GUI Local), puesto que sin esto, los TABS no van a funcionar.
261
Creamos un SubScreen, y lo asignamos al control TAB. La nica propiedad que tenemos que definir para el SubScreen es el nombre.
Dentro de los SubScreens no podemos colocar ningn control, puesto que son contenedores que admiten nicamente pantalla de tipo SubScreen. As que debemos crear dos pantallas ms, la 101 y 102, pero esta vez de tipo SubScreen. 262
Luego de haber creado las dos SubScreens, este ser el Flow Logic para la pantalla principal.
PROCESS BEFORE OUTPUT. MODULE STATUS_0100. CALL SUBSCREEN: SUBSCREEN_1 INCLUDING SY-REPID '0101'. CALL SUBSCREEN: SUBSCREEN_2 INCLUDING SY-REPID '0102'. PROCESS AFTER INPUT. MODULE USER_COMMAND_0100. CALL SUBSCREEN: SUBSCREEN_1,SUBSCREEN_2.
Con el CALL SUBSCREEN llamamos a cada una de las pantallas SubScreen que creamos. Con el INCLUDING referenciamos al programa control y al nmero de la pantalla.
263
Como podemos ver, en el PAI tambin utilizamos el CALL SUBSCREEN para llamar a las SubScreens. Como mencion lineas arriba, los componentes tendremos que colocarlos dentro de cada SubScreen, por lo cual vamos a comenzar con el nmero 0101. Vamos a crear un Box o Caja con los siguientes atributos.
Dentro del Box (Caja), vamos a crear un campo de texto para el cdigo del programa. Si queremos que est asociado con una tabla de la Base de Datos, tendremos que utilizar el nombre TABLACAMPO como nombre. En este caso, el nombre ser ZPROGRAMAS-ID. Vamos a agregar tambin un botn llamado PROCESAR y que va a tener como cdigo de funcin la palabra PROCESS.
con el
cdigo de funcin MODIFY. Este botn nos va a servir, puesto que una vez obtenidos los datos del programa, podremos modificarlos y mostrarlos en el segundo SubScreen. En el cual no podrn ser modificados.
Cabe destacar que aunque tengamos pensado utilizar dos SubScreens, los nombres de los componentes no pueden repetirse, es decir, no podemos crear el campo ZPROGRAMASNOM_PROG en ambas pantallas...Lo mejor sera crear una estructura para cada una de ellas y problema resuelto. Pero aqu simplemente vamos a utilizar variables para el segundo SubScreen.
265
Por lo tanto, vamos a tener V_NOM_PROG y V_NOMBRE. En el programa, deberemos declarar la tablas ZPROGRAMAS y ZLENGUAJES_PROG, crear las variables correspondientes y crear el componente TAB_CONTROL.
START-OF-SELECTION. CONTROLS TAB_CONTROL TYPE TABSTRIP. TAB_CONTROL-ACTIVETAB = 'TAB_1'. CALL SCREEN '100'.
La sentencia TAB_CONTROL-ACTIVETAB, indica que pestaa del TAB va a estar activa cuando ejecutemos el programa. Para el botn PROCESAR vamos a crear el siguiente form.
FORM OBTENER_DATOS. SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE,ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID. ENDFORM. "OBTENER_DATOS
266
Hacemos un INNER JOIN entre las dos tablas, y obtenemos los valores NOMBRE y NOM_PROG, los cuales son guardados en los Campos de Entrada/Salida del Dynpro. No debemos olvidarnos del USER-COMMAND.
MODULE USER_COMMAND_0100 INPUT. DATA: OK_CODE TYPE SY-UCOMM. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'PROCESS'. PERFORM OBTENER_DATOS. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
267
Cuando ejecutamos el programa, nos vamos a dar cuenta de algo bastante peculiar...Cuando ingresamos el primer cdigo, todo va bien, pero con el segundo, los datos se quedan pegados. Esto es porque estamos trabajando en un SubScreen y los datos no se actualizan directamente. Por suerte, y como debe ser, existe una funcin que actualiza los Dynpros. Para esto, debemos crear los siguientes TYPES y Tablas Internas.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TAB, FIELDNAME TYPE DYNPREAD-FIELDNAME, STEPL TYPE DYNPREAD-STEPL, FIELDVALUE TYPE DYNPREAD-FIELDVALUE, * *=====================================================*
268
FIELDINP TYPE DYNPREAD-FIELDINP, END OF TAB. TYPES: BEGIN OF DYNP, DYNUMB TYPE D020S-DNUM, END OF DYNP. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: MY_TAB TYPE STANDARD TABLE OF TAB, MY_DYNP TYPE STANDARD TABLE OF DYNP. * *=====================================================*
Nuestro FORM para actualizar el Dynpro ser el siguiente (Aunque primero debemos crear dos Field-Symbols.
FORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP. LOOP AT MY_DYNP ASSIGNING <FS_MY_DYNP>. CALL FUNCTION 'DYNP_UPDATE_FIELDS' EXPORTING DYNAME DYNUMB REQUEST TABLES = SY-CPROG = <FS_MY_DYNP>-DYNUMB = 'A'
269
El mdulo 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, podemos mejorar la rutina OBTENER_DATOS.
FORM OBTENER_DATOS. SELECT SINGLE NOMBRE NOM_PROG INTO (ZLENGUAJES_PROG-NOMBRE,ZPROGRAMAS-NOM_PROG) FROM ( ZPROGRAMAS INNER JOIN ZLENGUAJES_PROG ON ZPROGRAMAS~ID EQ ZLENGUAJES_PROG~ID ) WHERE ZPROGRAMAS~ID EQ ID.
IF SY-SUBRC EQ 0. APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-ID'. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-ID. APPEND INITIAL LINE TO MY_TAB ASSIGNING <FS_MY_TAB>. <FS_MY_TAB>-FIELDNAME = 'ZPROGRAMAS-NOM_PROG'. <FS_MY_TAB>-FIELDVALUE = ZPROGRAMAS-NOM_PROG. APPEND INITIAL LINE TO MY_TAB
270
ASSIGNING <FS_MY_TAB>. <FS_MY_TAB>-FIELDNAME = 'ZLENGUAJES_PROG-NOMBRE'. <FS_MY_TAB>-FIELDVALUE = ZLENGUAJES_PROG-NOMBRE. APPEND INITIAL LINE TO MY_DYNP ASSIGNING <FS_MY_DYNP>. <FS_MY_DYNP>-DYNUMB = '0101'. PERFORM ACTUALIZAR_DYNPRO TABLES MY_TAB MY_DYNP. ENDIF. ENDFORM. "OBTENER_DATOS
Primero, si el SELECT es exitoso, agregamos los campos del Dynpro a nuestra tabla MY_TAB, adems agregamos el nmero del Dynpro a nuestra tabla MY_DYNP. Finalmente llamamos al FORM ACTUALIZAR_DYNPRO pasando las tablas como parmetros. Con esto listo, podemos continuar con el botn MODIFICAR.
MODULE USER_COMMAND_0100 INPUT. DATA: OK_CODE TYPE SY-UCOMM. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'PROCESS'. PERFORM OBTENER_DATOS.
271
Creamos el nuevo FORM. (Aunque antes creamos un par de variables que estn relacionadas con los campos del segundo SubScreen).
FORM TRASPASAR_VALORES. CLEAR: V_NOM_PROG,V_NOMBRE. MOVE ZPROGRAMAS-NOM_PROG TO V_NOM_PROG. MOVE ZLENGUAJES_PROG-NOMBRE TO V_NOMBRE. ENDFORM. " TRASPASAR_VALORES
272
273
274
PROCESS BEFORE OUTPUT. MODULE STATUS_0100. MODULE LLENAR_LISTA_DESPLEGABLE. PROCESS AFTER INPUT. MODULE USER_COMMAND_0100.
Como era de esperarse, debemos crear algunas variables, tablas internas, un Type e inclusive un Type-Pool.
*=====================================================* * DECLARACION DE TYPES TYPE-POOLS: VRM. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: VALUES TYPE VRM_VALUES, FC_VALUES LIKE VALUES WITH HEADER LINE. *=====================================================* * DECLARACION DE VARIABLES DATA: ID TYPE VRM_ID. * *=====================================================* * *=====================================================* * *=====================================================*
Como ven, nuevamente necesitamos una tabla con cabecera...Esto es porque el componente Listbox sigue siendo parte del ABAP antiguo.
275
Este es el cdigo que utilizaremos para llenar con datos la lista, ya se que se ve un poco redundante, pero la estructura de la funcin que genera la lista as lo requiere.
MODULE LLENAR_LISTA_DESPLEGABLE OUTPUT. IF ID EQ SPACE. ID = 'ZPROGRAMAS-ID'. SELECT ID NOMBRE INTO (FC_VALUES-KEY,FC_VALUES-TEXT) FROM ZLENGUAJES_PROG. APPEND FC_VALUES. ENDSELECT. LOOP AT FC_VALUES. APPEND FC_VALUES TO VALUES. ENDLOOP. CALL FUNCTION 'VRM_SET_VALUES' EXPORTING ID VALUES EXCEPTIONS ID_ILLEGAL_NAME OTHERS ENDIF. ENDMODULE. " LLENAR_LISTA_DESPLEGABLE OUTPUT = 1 = 2. = ID = VALUES
276
Aunque no es nada recomendable utilizarlo, en este caso necesitamos el SELECT-ENDSELECT (El GOTO del ABAP). Necesitamos que los valores queden almacenados en la tabla VALUES que es la que vamos a pasar al mdulo de funciones VRM_SET_VALUES, que es el que finalmente crea la lista despegable. Si ejecutamos el programa, veremos que la lista est llena, pero no hace nada, puesto que si seleccionamos un lenguaje de programacin, no nos muestra los datos, adems, nos muestra el nombre del lenguaje en un espacio muy reducido, as que deberamos ampliar un poco su tamao, antes de poder continuar. As que vamos a hacer que cuando seleccionemos el lenguaje, se muestren los datos, sin necesidad de un botn auxiliar.
277
FORM OBTENER_DATOS. SELECT SINGLE ID_PROG NOM_PROG INTO (ZPROGRAMAS-ID_PROG,ZPROGRAMAS-NOM_PROG) FROM ZPROGRAMAS WHERE ID EQ ZPROGRAMAS-ID. IF SY-SUBRC NE 0. CLEAR: ZPROGRAMAS-ID_PROG,ZPROGRAMAS-NOM_PROG. ENDIF. ENDFORM. " OBTENER_DATOS
278
Ahora, cuando elegimos un valor de la lista desplegable, podemos obtener los datos asociados.
279
DATA: DYNPRO_VALUES TYPE TABLE OF DYNPREAD WITH HEADER LINE, FIELD_VALUE LIKE LINE OF DYNPRO_VALUES. DATA: DYNUM TYPE D020S-DNUM.
MODULE READ_DYNP_VALUES INPUT. FREE FIELD_VALUE. FREE DYNPRO_VALUES. FIELD_VALUE-FIELDNAME = 'ZPROGRAMAS-ID'. APPEND FIELD_VALUE TO DYNPRO_VALUES.
280
DYNUMB = '0100'. CALL FUNCTION 'DYNP_VALUES_READ' EXPORTING DYNAME DYNUMB TABLES DYNPFIELDS = DYNPRO_VALUES. READ TABLE DYNPRO_VALUES WITH KEY FIELDNAME = 'ZPROGRAMAS-ID'. IF SY-SUBRC EQ 0. ZPROGRAMAS-ID = DYNPRO_VALUES-FIELDVALUE. ENDIF. ENDMODULE. " READ_DYNP_VALUES INPUT = SY-CPROG = DYNUMB
Como podemos ver, tenemos que pasar el nmero del Dynpro, y el valor que queremos leer. Si la funcin puede leerlo, entonces lo asignamos a nuestro campo o a donde lo necesitemos.
281
282
esto, necesitaremos como parmetro de entrada la fecha de nacimiento del usuario y como salida podemos mostrar una tabla que contenga los campos aos, meses y das. Por lo tanto, necesitaremos crear una estructura que contenga dichos campos. Vamos a llamarla ZEDAD_STR.
En este caso, solo vamos a utilizar un parmetro de entrada, llamado FECHA_NAC de tipo SY-DATUM.
283
Como podemos ver, hay dos CheckBox, 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. En este caso, dejamos ambos como estn, es decir, mantenemos los valores por defecto. En la pestaa Changing (Cambiando), vamos a crear nuestro parmetro de salida, que har referencia a la estructura que hemos creado.
Para todos los parmetros existen un botn muy importante llamado Long text (Texto largo) . Este botn, nos permite crear un
texto de ayuda que indica que hace o que necesita el parmetro para funcionar correctamente. Basta con hacer clic en el botn Create (Crear) para ingresar al editor. Escribimos un pequeo texto descriptivo, grabamos, activamos y salimos.
284
Luego de esto, podemos darnos cuenta de que el botn ha cambiado, indicndonos que el texto ha sido asignado correctamente.
Finalmente, podemos pasar a la pestaa de Source Code (Cdigo Fuente) en donde vamos a crear el cdigo necesario para que nuestra funcin...funcione. Claro, no va a ser el clculo ms exacto, pero a modo de ejemplo nos va a ser til. Antes de comenzar con el cdigo, es importante saber que podemos asignar excepciones, que son errores que puede encontrar la funcin, por ejemplo, si la fecha de nacimiento ingresada como parmetro es mayor que la fecha actual, deberamos mostrar un mensaje de error. Esto lo hacemos ingresando a la pestaa Exceptions (Excepciones).
FUNCTION ZDUMMY_FUNCTION. *"----------------------------------------------------*"*"Local Interface: *" *" *" IMPORTING REFERENCE(FECHA_NAC) TYPE CHANGING SY-DATUM
285
ZEDAD_STR
*"----------------------------------------------------DATA: ZYEARS(4) TYPE C, ZMONTHS(2) TYPE C, ZDAYS(2) TYPE C. IF FECHA_NAC GT SY-DATUM. RAISE EDAD_FUERA_RANGO. ENDIF. ZYEARS = FECHA_NAC+0(4). ZMONTHS = FECHA_NAC+4(2). ZDAYS = FECHA_NAC+6(2). ZYEARS = SY-DATUM+0(4) - ZYEARS. IF SY-DATUM+4(2) LT ZMONTHS. ZYEARS = ZYEARS - 1. ZMONTHS = SY-DATUM+4(2) + 1. ENDIF. IF SY-DATUM+6(2) LT ZDAYS. ZDAYS = 30 - ZDAYS. ZMONTHS = ZMONTHS - 1. ZDAYS = ZDAYS + SY-DATUM+6(2). ENDIF. TABLA_EDAD-ZYEARS = ZYEARS. TABLA_EDAD-ZMONTHS = ZMONTHS. TABLA_EDAD-ZDAYS = ZDAYS.
286
ENDFUNCTION.
Declaramos 3 variables, una para guardar el ao, otra el mes y la ltima los das. Adems una variable auxiliar para los meses.
Si la fecha de nacimiento ingresada, es menor a la fecha actual del sistema, lanzamos un mensaje de error.
En SAP, las fechas se almacenan en un orden inverso, por lo tanto, al ingresar nosotros 22.11.1977 se almacena como 19771122. Entonces, para poder obtener los aos, meses y das en variables, utilizamos posiciones de inicio y cantidad de caracteres, es decir, al
287
tener nostros FECHA_NAC+0(4) estamos diciendo, Toma 4 caracteres, comenzando desde el carcter 0. En otras palabras 1977. Restamos el ao actual, menos el ao del parmetro.
IF SY-DATUM+4(2) LT ZMONTHS. ZYEARS = ZYEARS - 1. ZMONTHS_AUX = 12 - ZMONTHS. ZMONTHS = SY-DATUM+4(2) + ZMONTHS. ENDIF.
Si el mes actual es menor que el mes del parmetro, entonces debemos restar un ao. Restamos la cantidad de meses a 12, para saber cuantos hay de diferencia, finalmente, sumamos esos meses de diferencia.
IF SY-DATUM+6(2) LT ZDAYS. ZDAYS = 30 - ZDAYS. ZMONTHS = ZMONTHS - 1. ZDAYS = ZDAYS + SY-DATUM+6(2). ENDIF.
Si los das actuales son menores que los das del parmetro, entonces a 30 le restamos la cantidad de das. Restamos 1 a meses y sumamos los das actuales ms los das que obtuvimos al hacer la resta de 30 menos los das del parmetro. Para probar nuestra funcin, simplemente debemos ejecutarla presionando la tecla F8 o el botn Test/Exectute (Probar/Ejecutar) .
288
Ingresamos una fecha de nacimiento y lo ejecutamos, ya sea con el botn Execute (Ejecutar) o presionando F8 . Adems podramos
Para ver ms claramente el resultado, debemos hacer clic en Details View/Edit (Visualizar/Editar Detalles) . 289
30 Aos, 01 mes y 09 das. Si queremos ver el resultado con un mayor detalle, deberemos presionar el botn Single Entry (Entrada Individual) o presionar los botones Shift + F7 .
Ahora que ya vimos que nuestra funcin hace lo que tiene que hacer, es hora de llamarla desde un programa.
290
*=====================================================* * DECLARACION DE TABLAS DATA: TABLA_EDAD TYPE ZEDAD_STR. *=====================================================* * Selection screen SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME. PARAMETERS: P_FECHA TYPE SY-DATUM. SELECTION-SCREEN END OF BLOCK DATA. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CALL FUNCTION 'ZDUMMY_FUNCTION' EXPORTING FECHA_NAC CHANGING TABLA_EDAD EXCEPTIONS EDAD_FUERA_RANGO = 1 OTHERS IF SY-SUBRC <> 0. WRITE: 'La edad ingresada est fuera del rango'. ELSE. WRITE: 'Su edad actual es', TABLA_EDAD-ZYEARS, 'Aos', = 2. = TABLA_EDAD = P_FECHA * *=====================================================* * *=====================================================* * *=====================================================*
291
El cdigo es bastante sencillo y no necesita mayor explicacin. Llamamos a la funcin, obtenemos los datos y los mostramos en pantalla.
Introduccin BAPIS
Una BAPI (Business Application Programming Interface Interface de Programacin de Aplicaciones de Negocio), no es en el fondo ms que un mdulo de funciones con caractersticas de RFC. Aunque las BAPIs son utilizadas para realizar tareas especficas, como por ejemplo, crear pedidos, realizar contabilizaciones, cargar datos maestros, etc. 292
Las BAPIs son estables, puesto que cuentan con muchos mecanismos de control y aseguramiento. Adems, encapsulan operaciones complejas en una simple interfaz. Por eso, las BAPIs cuentan con su propia transaccin llamada justamente BAPI.
293
Creando un ALV
Para crear un ALV, necesitamos una funcin muy importante llamada REUSE_ALV_GRID_DISPLAY, que es la que finalmente crea todo el diseo visual y la gran mayora de las funcionalidades standard que nos ofrecen estos reportes dinmicos. Otro punto importante, es el uso de un TYPE-POOLS, llamado SLIS. Este TYPE-POOLS, contiene todas las definiciones de variables y tablas internas que necesitamos para poder trabajar, as que veamos como sera el esqueleto del programa. Lo primero que hay que hacer, es obtener los datos tal como lo haramos en un programa normal, puesto que una vez que tengamos lista la tabla interna, ser muy sencillo generar el ALV.
294
*=====================================================* * DECLARACION DE TABLAS TABLES: ZPROGRAMAS. *=====================================================* * DECLARACION DE TYPE-POOLS TYPE-POOLS: SLIS. *=====================================================* * 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. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS. *=====================================================* * Selection screen SELECTION-SCREEN BEGIN OF BLOCK DATA WITH FRAME. SELECT-OPTIONS: * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================* * *=====================================================*
295
S_IDPROG FOR ZPROGRAMAS-ID_PROG. SELECTION-SCREEN END OF BLOCK DATA. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM OBTENER_DATOS. *&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM 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. ENDFORM. " 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 visualizacin.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV, * *=====================================================*
296
*=====================================================* * DECLARACION DE VARIABLES DATA: G_PROGRAM TYPE SY-REPID, G_TITULO TYPE SY-TITLE, G_REPID TYPE SY-REPID, GS_SORT TYPE SLIS_T_SORTINFO_ALV. * *=====================================================*
Vamos a agregar un nuevo evento, que se dispara cuando se ha terminado la seleccin de datos.
En este evento, vamos a agregar una serie de funciones que se van a encargar de formar el ALV.
*=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM INIT_LAYOUT. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. PERFORM BUILD_SORT. PERFORM F_GENERAR_LISTA_ALV. * *=====================================================*
297
Indicamos que queremos que el reporte se muestre con colores intercalados por registro, es decir, el primero blanco, el segundo gris, el tercero blanco, etc.
FORM BUILD_SORT. APPEND INITIAL LINE TO GS_SORT ASSIGNING <FS_SORT>. <FS_SORT>-SPOS = 1. <FS_SORT>-FIELDNAME = 'ID_PROG'. <FS_SORT>-UP = 'X'. ENDFORM. " BUILD_SORT
Primero, indicamos el nmero de la columna por la cual vamos a ordenar la lista, segundo, indicamos el nombre del campo relacionado a dicha columna, ordenacin va a ser ascendente. finalmente indicamos que la
298
DATA: L_FIELDCAT TYPE SLIS_FIELDCAT_ALV. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-FIELDNAME = 'ID_PROG'. L_FIELDCAT-SELTEXT_L = 'Id'. L_FIELDCAT-COL_POS = 1. L_FIELDCAT-OUTPUTLEN = 5. APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-FIELDNAME = 'NOM_PROG'. L_FIELDCAT-SELTEXT_L = 'Nombre Programa'. L_FIELDCAT-COL_POS = 2. L_FIELDCAT-OUTPUTLEN = 15. APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-FIELDNAME = 'NOMBRE'. L_FIELDCAT-SELTEXT_L = 'Nombre Lenguaje'. L_FIELDCAT-COL_POS = 3. L_FIELDCAT-OUTPUTLEN = 15. APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-FIELDNAME = 'ENTORNO'. L_FIELDCAT-SELTEXT_L = 'Entorno'. L_FIELDCAT-COL_POS = 4. L_FIELDCAT-OUTPUTLEN = 10.
299
APPEND L_FIELDCAT TO T_FIELDCAT. CLEAR L_FIELDCAT. L_FIELDCAT-TABNAME = 'T_PROGRAMAS'. L_FIELDCAT-FIELDNAME = 'CONEX_SAP'. L_FIELDCAT-SELTEXT_L = 'Conexin con SAP'. L_FIELDCAT-COL_POS = 5. L_FIELDCAT-OUTPUTLEN = 15. APPEND L_FIELDCAT TO T_FIELDCAT. ENDFORM. "FORMATEAR_DATOS_ALV_DET
La tabla L_FIELDCAT se llena con todos los campos que queremos mostrar en nuestro ALV, esta es apendada a la tabla T_FIELDCAT, que luego es usada para llenar la tabla I_FIELDCAT que se pasa finalmente al ALV. TABNAME es el nombre de la tabla que contiene la estructura del ALV. FIELDNAME es el nombre del campo que queremos mostrar. SELTEXT_L es el texto que se va a mostrar en el campo. COL_POS es la posicin que va a tener el campo dentro del ALV. OUTPUTLEN es la cantidad de caracteres de salida. Este FORM es el ms importante, puesto que indica que campos deben leerse, de que tamao deben de ser mostrados, en que posicin, y que texto va a describirlos en la cabecera. En este ejemplo hemos utilizado pocos campos, y hasta donde mi experiencia personal ha llegado, el ALV soporta hasta 65 campos sin ningn problema. Con todos los ingredientes listos, solo nos falta llamar al ALV.
300
FORM F_GENERAR_LISTA_ALV. G_PROGRAM = SY-REPID. G_TITULO = 'Lista de Programas'. 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. EXIT. ENDIF. ENDFORM. " F_GENERAR_LISTA_ALV = 1 = 2. = 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. (Esta variable se asigna al parmetro I_CALLBACK_PROGRAM. G_TITULO es el ttulo que va a llevar el listado ALV. (Esta variable se asigna al parmetro I_GRID_TITLE).
301
GS_LAYOUT almacena el formato del listado. (Esta tabla se asigna al parmetro IS_LAYOUT). I_FIELDCAT almacena los campos que conforman el ALV. (Esta tabla se asigna al parmetro IT_FIELDCAT). GS_SORT almacena el orden del ALV. (Esta tabla se asigna al parmetro IT_SORT). T_PROGRAMAS es la tabla que almacena todos los registros obtenidos en el INNER JOIN. (Esta tabla se asigna al parmetro T_OUTTAB). Ahora, podemos ejecutar el programa.
302
Ahora que ya vimos como es un ALV, investigemos un poco. Supongamos que no queremos que sea de tipo ZEBRA, as que cambiamos el comando.
FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = ' '. ENDFORM. " INIT_LAYOUT
303
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV, I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV, GS_LAYOUT TYPE SLIS_LAYOUT_ALV, GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER, I_EVENTS TYPE SLIS_T_EVENT. * *=====================================================*
GS_LIST_TOP_OF_PAGE almacena los ttulo de la cabecera, mientras que I_EVENT controla los eventos del ALV. Adems necesitamos dos nuevas funciones.
*=====================================================* * END-OF-SELECTION END-OF-SELECTION. PERFORM INIT_LAYOUT. PERFORM FORMATEAR_DATOS_ALV_DET USING I_FIELDCAT[]. PERFORM F_FORMATO_PAGE CHANGING GT_LIST_TOP_OF_PAGE. PERFORM F_FORMATEAR_EVENTOS_ALV USING I_EVENTS[]. PERFORM BUILD_SORT. PERFORM F_GENERAR_LISTA_ALV. * *=====================================================*
304
DATA: GS_LINE TYPE SLIS_LISTHEADER. CLEAR GS_LINE. GS_LINE-TYP = 'H'. CONCATENATE 'FECHA:' SY-DATUM INTO GS_LINE-INFO SEPARATED BY SPACE. APPEND GS_LINE TO GT_TOP_OF_PAGE. CLEAR GS_LINE. GS_LINE-TYP = 'H'. CONCATENATE 'HORA:' SY-UZEIT INTO GS_LINE-INFO SEPARATED BY SPACE. APPEND GS_LINE TO GT_TOP_OF_PAGE. ENDFORM. "F_FORMATO_PAGE
GS_LINE-TYP es el tipo de cabecera, H equivale a Header (Cabecera). GS_LINE-INFO es el texto que se va a mostrar. GS_LINE se adiciona a la tabla GT_TOP_OF_PAGE. Mientras que el segundo, nos permite definir el evento que requiere el ALV para poder activar la cabecera.
FORM F_FORMATEAR_EVENTOS_ALV USING P_EVENTS TYPE SLIS_T_EVENT. DATA: L_EVENTS TYPE SLIS_ALV_EVENT.
305
CLEAR L_EVENTS. L_EVENTS-NAME = 'TOP_OF_PAGE'. L_EVENTS-FORM = 'TOP_OF_PAGE'. APPEND L_EVENTS TO P_EVENTS. ENDFORM. "F_FORMATEAR_EVENTOS_ALV
Declaramos una variable llamada L_EVENTS que controla los eventos. En este caso, queremos que el evento sea TOP_OF_PAGE es decir, la cabecera del ALV. Para terminar, un ltimo FORM que asigna la cabecera al ALV.
FORM TOP_OF_PAGE. CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE' EXPORTING IT_LIST_COMMENTARY = GT_LIST_TOP_OF_PAGE. ENDFORM. "TOP_OF_PAGE
La funcin REUSE_ALV_COMMENTARY_WRITE es la coloca el ttulo en el ALV. Y como utilizamos una funcin que crea el ALV, debemos indicarle que evento tiene que ser activado.
306
G_TITULO = 'Lista de Programas'. 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. EXIT. ENDIF. ENDFORM. " F_GENERAR_LISTA_ALV = 1 = 2. = T_PROGRAMAS = ' ' = G_TITULO = GS_LAYOUT = I_FIELDCAT = GS_SORT[] = I_EVENTS I_CALLBACK_PROGRAM = G_PROGRAM
Debemos agregar el parmetro IT_EVENTS que recibe la tabla I_EVENTS, que contiene los detalles del evento. Ahora, cuando lo ejecutamos, podremos ver esto.
307
Claro que la fecha y lo hora se ven bastante mal, esto es porque se muestran en el formato interno de SAP. Podemos corregirlos de una manera muy sencilla. Simplemente debemos de crear dos variables de tipo texto, obtener los componentes de la fecha y la hora, y concatenarlos utilizando separadores tales como / y ., para luego asignarlos a nuestra tabla de cabecera.
FORM F_FORMATO_PAGE CHANGING GT_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER. DATA: GS_LINE TYPE SLIS_LISTHEADER, FECHA(10) TYPE C, HORA(10) TYPE C. CONCATENATE SY-DATUM+6(2) SY-DATUM+4(2) SY-DATUM+0(4) INTO FECHA SEPARATED BY '/'. CONCATENATE SY-UZEIT+0(2) SY-UZEIT+2(2) SY-UZEIT+4(2)
308
INTO HORA SEPARATED BY ':'. CLEAR GS_LINE. GS_LINE-TYP = 'H'. CONCATENATE 'FECHA:' FECHA INTO GS_LINE-INFO SEPARATED BY SPACE. APPEND GS_LINE TO GT_TOP_OF_PAGE. CLEAR GS_LINE. GS_LINE-TYP = 'H'. CONCATENATE 'HORA:' HORA INTO GS_LINE-INFO SEPARATED BY SPACE. APPEND GS_LINE TO GT_TOP_OF_PAGE. ENDFORM. "F_FORMATO_PAGE
309
*=====================================================* * DECLARACION DE VARIABLES DATA: G_PROGRAM TYPE SY-REPID, G_TITULO TYPE SY-TITLE, G_REPID TYPE SY-REPID, GS_SORT TYPE SLIS_T_SORTINFO_ALV, G_USER_COMMAND TYPE SLIS_FORMNAME VALUE 'USER_COMMAND'. * *=====================================================*
La variable G_USER_COMMAND tiene el valor por defecto USER_COMMAND, que es el nombre del evento que va a manejar. Tambin, debemos asignar un cdigo de funcin.
310
FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'. ENDFORM. " INIT_LAYOUT
GS_LAYOUT-F2CODE guarda el nombre que le asignamos al cdigo de funcin que en este caso es FUNCION. Debemos crear una nueva funcin para poder establecer cual va a ser la accin ha tomar por el ALV cuando el usuario haga doble clic sobre un registro. Antes de empezar, debemos declarar un nuevo Field-Symbol.
*=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT, <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. * *=====================================================*
FORM USER_COMMAND USING R_UCOMM LIKE SY-UCOMM RS_SELFIELD TYPE SLIS_SELFIELD. DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. CHECK NOT RS_SELFIELD-TABNAME IS INITIAL. CASE R_UCOMM. WHEN 'FUNCION'. READ TABLE T_PROGRAMAS INDEX RS_SELFIELD-TABINDEX
311
ASSIGNING <FS_PROGRAMAS>. CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-NOMBRE INTO MENSAJE SEPARATED BY SPACE. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. ENDCASE. ENDFORM. "USER_COMMAND
Declaramos una variable MENSAJE la cual va a contener el texto que queremos mostrar al hacer doble clic en una lnea. Revisamos que la tabla RS_SELFIELD-TABNAME no est vaca, es decir, que hayamos seleccionado un registro. Cuando el cdigo de funcin que hemos definido, es decir FUNCION, podemos continuar. Leemos la tabla interna con el ndice del registro seleccionado. Concatenamos algunos campos de la tabla en nuestra variable MENSAJE y llamamos a la funcin MESSAGE_TEXT_DISPLAY_WITH_PARA que muestra un mensaje en la pantalla. Como era de esperarse, debemos primero asignar un nuevo valor a nuestra funcin creadora de ALVs.
312
FORM F_GENERAR_LISTA_ALV. G_PROGRAM = G_TITULO = SY-REPID. G_TITULO = 'Lista de Programas'. 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. ENDIF. ENDFORM. " F_GENERAR_LISTA_ALV = 1 = 2. = T_PROGRAMAS = ' ' = G_PROGRAM = G_TITULO = GS_LAYOUT = 'A' = I_FIELDCAT = GS_SORT[] = I_EVENTS
I_CALLBACK_USER_COMMAND = G_USER_COMMAND
Agregamos el parmetro I_CALLBACK_USER_COMMAND que permite hacer que funcionen los eventos, a este parmetro le pasamos la variable G_USER_COMMAND.
313
El parmetro I_SAVE = A nos permite manejar las variantes. Cuando ejecutamos el programa, bastar con hacer un doble clic en cualquier registro para ejecutar el evento.
Si queremos hacer un solo clic, podemos entonces mejorar un poco el reporte. Hacemos lo siguiente.
FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'. ENDFORM. " INIT_LAYOUT
GS_LAYOUT-KEY_HOTSPOT indica que los campos pueden ser del tipo enlace.
314
L_FIELDCAT-FIELDNAME = 'ID_PROG'. L_FIELDCAT-SELTEXT_L = 'Id'. L_FIELDCAT-KEY = 'X'. L_FIELDCAT-COL_POS = 1. L_FIELDCAT-OUTPUTLEN = 5. APPEND L_FIELDCAT TO T_FIELDCAT.
Como pueden ver, los valores del campo ID_PROG, estn subrayados, lo cual indica que son campos claves para la activacin con un clic por parte del usuario.
315
*=====================================================* * 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, LINE_COLOR(4) TYPE C, END OF TY_PROGRAMAS. * *=====================================================*
Agregamos un campo llamado LINE_COLOR que determina el color que queremos utilizar. Luego de obtener los datos, debemos determinar que lnea debe pintarse.
FORM 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. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. IF <FS_PROGRAMAS>-NOMBRE EQ 'RUBY'. <FS_PROGRAMAS>-LINE_COLOR = 'C510'. MODIFY T_PROGRAMAS FROM <FS_PROGRAMAS>. ENDIF.
316
Si el registro tiene el valor RUBY en el campo NOMBRE, entonces pintamos la lnea de verde utilizando el cdigo C510. Finalmente, debemos indicar que queremos pintar una lnea.
FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'. GS_LAYOUT-INFO_FIELDNAME = 'LINE_COLOR'. ENDFORM. " INIT_LAYOUT
Como ven, es bastante sencillo, aunque no necesariamente til, pero ya me tocado hacerlo en algn proyecto, as que espero les sirva tambin a ustedes.
317
Ahora que ya estamos felices con nuestro colorido ALV, podemos pasar a algo un poco ms complicado, pero simple de todos modos. Vamos a colorear celdas individuales en un ALV. Primero, tenemos que crear una tabla interna auxiliar y modificar un poco la tabla que tenamos, esto porque al menos en el NetWeaver no se pueden hacer SELECTs a una tabla interna con DEEP STRUCTURE, es decir, una tabla interna que tiene como campo a otra tabla interna.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS_AUX, 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_AUX. 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, COLOR_CELL TYPE LVC_T_SCOL, END OF TY_PROGRAMAS. * *=====================================================*
318
Debemos crear un nuevo TYPES, y modificar el original agregando el campo COLOR_CELL que es en realidad, una tabla interna dentro de nuestra tabla interna. WA_COLOR y IT_COLOR nos sirven para almacenar algunos parmetros adicionales necesarios para el color de la celda.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_PROGRAMAS_AUX TYPE STANDARD TABLE OF TY_PROGRAMAS_AUX, I_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV, I_SORT_ALV TYPE SLIS_T_SORTINFO_ALV, GS_LAYOUT TYPE SLIS_LAYOUT_ALV, GT_LIST_TOP_OF_PAGE TYPE SLIS_T_LISTHEADER, I_EVENTS TYPE SLIS_T_EVENT, WA_COLOR TYPE LVC_S_SCOL, IT_COLOR TYPE TABLE OF LVC_S_SCOL. * *=====================================================*
Creamos una tabla interna basada en nuestro nuevo TYPE. Y agregamos un nuevo Field-Symbol.
*=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_SORT> LIKE LINE OF GS_SORT, <FS_PROGRAMAS> LIKE LINE OF * *=====================================================*
319
Nuestro cdigo va a tener que cambiar un poco. Primero, debemos hacer el SELECT a nuestra tabla interna auxiliar, luego, pasar todos los campos a nuestra tabla interna original para recin poder determinar cuales son los campos que tienen que estar dibujados de algn color. No es dificil, pero definitivamente quita ms tiempo.
FORM OBTENER_DATOS. 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. LOOP AT T_PROGRAMAS_AUX ASSIGNING <FS_PROGRAMAS_AUX>. REFRESH IT_COLOR. MOVE 'NOMBRE' TO WA_COLOR-FNAME. MOVE '6' TO WA_COLOR-COLOR-COL. APPEND WA_COLOR TO IT_COLOR. APPEND INITIAL LINE TO T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. MOVE-CORRESPONDING <FS_PROGRAMAS_AUX> TO <FS_PROGRAMAS>. IF <FS_PROGRAMAS_AUX>-NOMBRE EQ 'RUBY'.
320
Debemos asignar el nombre del campo que se va a colorear a la tabla WA_COLOR-FNAME. Asignamos el color que queremos para la celda (En este caso, 6 es rojo) a la tabla WA_COLOR-COLOR-COL (Como ven, WA_COLOR tiene una tabla DEEP llamada COLOR). Apendamos WA_COLOR a la tabla IT_COLOR. Asignamos los registros de la tabla auxiliar a la tabla original y verificamos si el campo NOMBRE es igual a RUBY, en ese caso, asignamos la tabla IT_COLOR al DEEP STRUCTURE COLOR_CELL de nuestra tabla original. Finalmente, el INIT_LAYOUT tambin cambia, puesto que como estamos utilizando una tabla interna para contener los colores, debemos utilizar los atributos del Layout, indicndoles que ahora nos toca manejar campos y no registros.
FORM INIT_LAYOUT. GS_LAYOUT-ZEBRA = ' '. GS_LAYOUT-F2CODE = 'FUNCION'. GS_LAYOUT-KEY_HOTSPOT = 'X'. GS_LAYOUT-COLTAB_FIELDNAME = 'COLOR_CELL'.
321
ENDFORM.
" INIT_LAYOUT
El campo COLTAB_FIELDNAME indica el tipo de evento que se va a aplicar a la columna de la lista, en este caso COLOR_CELL, es decir, pintar una celda. El ALV quedara as.
Ahora que ya sabemos como jugar con los eventos y con algunas propiedades del ALV, sera bueno que tambin conocieramos un poco de su barra de mens, que adems de ser Standard, nos brinda toda la funcionalidad que podamos necesitar, por lo cual, muy rara vez tendremos que agregar botones adicionales.
322
Orden Ascendente
Orden Descendente
323
324
Fichero local
325
Destinatario de Correo
326
Funcin Grfica
Modificar Disposicin
327
Seleccionar Disposicin
Grabar disposicin
328
Informacin
329
Qu es la Orientacin a Objetos?
La Programacin Orientada a Objetos, es una serie de reglas, sentencias y liniamientos que se deben seguir para poder moldear procesos del mundo real. Es decir, con la POO nosotros podemos de una manera ms clara y sencilla, representar situaciones y/o procesos.
330
Existen muchos puntos que debemos conocer primero y que son anlogos en casi todos los lenguajes de programacin orientados a objetos, y por supuesto, ABAP Objects no es la excepcin. Una vez que conozcamos estos conceptos, podremos ahondar en el ABAP Objects, con ejemplos sencillos que ayuden a adquirir una base slida para programar con este nuevo modelo de negocio. Cabe destacar, que si bien en un escenario ideal, toda la programacin debera ser orientada a objetos, esto no ocurre en los escenarios reales. Muchas veces, se utiliza una combinacin de ambas fuerzas. Por lo cual, no es imperativo desarrollar aplicaciones 100% OO...Sino tal vez un 60-40% sera suficiente (Dependiendo del caso, claro est).
travs de la transaccin SE24 (Class Builder). Las clases estn compuestas por diferentes secciones: o Atributos Son los datos internos dentro de una
clase. Pueden ser definidos como cualquier tipo de dato ABAP. Existen dos tipos de atributos, de instancia y estticos. Para utilizar atributos de instancia, es necesario crear un objeto. Los atributos estticos no requieren de un objeto para poder ser utilizados. o Mtodos Son los procedimientos de la clase. Pueden acceder a todos los atributos de una clase y por lo tanto modificarlos. Son muy parecidos a los mdulos de funcin. De igual manera, existen mtodos de instancia (Pueden acceder a todos los atributos de la clase) y mtodos estticos (Solamente pueden acceder a los atributos estticos de la clase). Las clases poseen dos fases importantes. La primera es la de Definicin (Es donde se declaran los atributos y los mtodos) y la segunda es la de Implementacin (En donde se define cual va a ser la funcionalidad de cada mtodo). Un pequeo ejemplo de una clase.
332
*-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION. *DEFINICIN DE LA CLASE PUBLIC SECTION. *SECCIN PBLICA DE LA CLASE METHODS: *MTODOS FACTORIAL. PRIVATE SECTION. *SECCIN PRIVADA DE LA CLASE ENDCLASS. "C_MATH DEFINITION * *-----------------------------------------------------*
*-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. *IMPLEMENTACIN DE LA CLASE METHOD FACTORIAL. *DEFINICIN DE UN MTODO ENDMETHOD. ENDCLASS. "FACTORIAL "C_MATH IMPLEMENTATION * *-----------------------------------------------------*
Las clases pueden utilizar los llamados Constructores, que lo nico que hacen, es inicializar un objeto con valores en el mismo momento que est siendo creado. Esto es til cuando necesitamos que el objeto tenga un valor por defecto, si es que el programa no se lo asigna. Es decir, si un usuario no asigna un valor a la hora de ejecutar el programa, nuestro objeto siempre tendr un valor gracias al constructor. 333
*-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION. *DEFINICIN DE LA CLASE PUBLIC SECTION. *SECCIN PBLICA DE LA CLASE METHODS: *MTODOS CONSTRUCTOR IMPORTING NAME TYPE STRING, FACTORIAL. PRIVATE SECTION. *SECCIN PRIVADA DE LA CLASE ENDCLASS. "C_MATH DEFINITION * *-----------------------------------------------------*
*-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. *IMPLEMENTACIN DE LA CLASE METHOD CONSTRUCTOR. WRITE:/ NAME. *ENVIAMOS EL PARMETRO AL CONSTRUCTOR DE LA CLASE ENDMETHOD. METHOD FACTORIAL. *DEFINICIN DE UN MTODO ENDMETHOD. ENDCLASS. "FACTORIAL "C_MATH IMPLEMENTATION "CONSTRUCTOR * *-----------------------------------------------------*
Las clases pueden ser definidas utilizando Herencias, que no es ms que crear una clase a partir de otra existente. Esto nos sirve para 334
agregar funcionalidades que queremos que se encuentren separadas. Es decir, nosotros podemos crear una clase que obtenga el nmero de factura de un pedido, y podemos crear otra clase que herede de nuestra clase factura, pero que adems, nos de la posibilidad de obtener la cuenta contrato de dicha factura. As, tenemos dos clases, una se cre heredando caractersticas de la primera, pero le agreg una funcionalidad adicional, hacindolas distintas e independientes. La clase que brinda su funcionalidad, es llamada una Super Clase y la que ha heredado dichas funcionalidades, es llamada una Sub Clase. Una Sub Clase se define de la siguiente manera.
*-----------------------------------------------------* * CLASS C_SUPERMATH DEFINITION CLASS C_SUPERMATH DEFINITION. ENDCLASS. *Definicin de la clase *-----------------------------------------------------* * CLASS C_MATH DEFINITION CLASS C_MATH DEFINITION INHERITING FROM C_SUPERMATH . *Hereda de C_SUPERMATH PUBLIC SECTION. *Seccin Pblica de la clase METHODS: *Mtodos FACTORIAL. * *-----------------------------------------------------* "C_SUPERMATH DEFINITION * *-----------------------------------------------------*
335
*-----------------------------------------------------* * CLASS C_MATH IMPLEMENTATION CLASS C_MATH IMPLEMENTATION. *IMPLEMENTACIN DE LA CLASE METHOD FACTORIAL. *DEFINICIN DE UN MTODO ENDMETHOD. ENDCLASS. "FACTORIAL "C_MATH IMPLEMENTATION * *-----------------------------------------------------*
Objeto: Los objetos son instancias de una clase. Es decir, son copias que poseen la misma funcionalidad de la clase que los cre. No existe un lmite acerca de la cantidad de objetos que se pueden crear a partir de una clase, por lo cual, no hay preocuparse. Cada objeto creado a partir de una clase, se comporta como un elemento completamente independiente de los dems.
*Definimos un tipo de dato que se *referiencia a la clase C_MATH DATA DESCR_REF TYPE REF TO C_MATH. *Creamos e instanciamos un objeto *con referencia al tipo que creamos. CREATE OBJECT DESCR_REF.
336
337
*-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION. METHOD MAIN. CALL SELECTION-SCREEN '101' STARTING AT 10 10. IF SY-SUBRC NE 0. EXIT. ENDIF. ENDMETHOD. METHOD SET_FACT. FACT = 1. IF NUM GT 0. DO NUM TIMES. FACT = FACT * SY-INDEX. ENDDO. ENDIF. ENDMETHOD. METHOD GET_RESULT. WRITE: 'El Factorial es: ', ME->FACT. ENDMETHOD. ENDCLASS. START-OF-SELECTION. C_FACTORIAL=>MAIN( ). DATA MY_OBJ TYPE REF TO C_FACTORIAL. CREATE OBJECT MY_OBJ. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). CALL METHOD MY_OBJ->GET_RESULT. "GET_RESULT "FACTORIAL IMPLEMENTATION "SET_FACT "MAIN
338
Este cdigo se puede ver un poco complicado, extrao e innecesario, pero creanme que con el tiempo uno se acostumbra y la verdad es que es lo mejor programar as. Revisemos un poco el cdigo antes de ejecutarlo.
SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. PARAMETERS NUMBER TYPE I. SELECTION-SCREEN END OF SCREEN 101.
Declaramos un SELECTION-SCREEN pero utilizando un tipo ventana, esto para poder llamarlo desde nuestra clase.
*-----------------------------------------------------* * CLASS FACTORIAL DEFINITION * *-----------------------------------------------------* CLASS C_FACTORIAL DEFINITION. PUBLIC SECTION. CLASS-METHODS: MAIN. METHODS: SET_FACT IMPORTING NUM TYPE I, GET_RESULT RETURNING VALUE(FACT) TYPE I. PRIVATE SECTION. DATA FACT TYPE I. ENDCLASS. "FACTORIAL DEFINITION
Creamos nuestra clase C_FACTORIAL. En la seccin pblica, definimos un CLASS-METHOD, es decir, un mtodo de instacia. Adems, declaramos dos mtodos, SET_FACT que recibe un
339
parmetro NUM y GET_RESULT que retorna el valor final del programa. En la seccin privada, declaramos una variable llamada FACT, que es la que va a tener el resultado del factorial y es la variable que va a imprimir GET_RESULT.
*-----------------------------------------------------* * CLASS FACTORIAL IMPLEMENTATION * *-----------------------------------------------------* CLASS C_FACTORIAL IMPLEMENTATION. METHOD MAIN. CALL SELECTION-SCREEN '101' STARTING AT 10 10. IF SY-SUBRC NE 0. EXIT. ENDIF. ENDMETHOD. METHOD SET_FACT. FACT = 1. IF NUM GT 0. DO NUM TIMES. FACT = FACT * SY-INDEX. ENDDO. ENDIF. ENDMETHOD. METHOD GET_RESULT. WRITE: 'El Factorial es: ', ME->FACT. ENDMETHOD. ENDCLASS. "GET_RESULT "FACTORIAL IMPLEMENTATION "SET_FACT "MAIN
340
En el mtodo MAIN, llamamos a nuestra pantalla para poder capturar el valor ingresado por el usuario. En el mtodo SET_FACT realizamos el algoritmo para determinar el factorial. En el mtodo GET_RESULT imprimimos el valor de la variable FACT. Como se darn cuenta, utilizamos ME->FACT para llamar a la variable, esto es porque este mtodo no recibe parmetros, por lo cual necesita obtener el valor de la misma clase, pero como la variable est en la seccin privada, entonces necesitamos acceder a ella definiendo el nombre de la clase y la variable, con lo cual quedara as C_FACTORIAL->FACT. Felizmente, y para no escribir tanto, podemos escribirlo as ME->FACT, donde ME equivale a C_FACTORIAL.
START-OF-SELECTION. C_FACTORIAL=>MAIN( ). DATA MY_OBJ TYPE REF TO C_FACTORIAL. CREATE OBJECT MY_OBJ. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). CALL METHOD MY_OBJ->GET_RESULT.
Llamamos al mtodo esttico MAIN, declaramos un objeto de la clase C_FACTORIAL, y lo creamos. Llamamos al mtodo SET_FACT pasando el valor del parmetro obtenido en la ventana del SELECTION-SCREEN. Llamamos al mtodo GET_RESULT para mostrar el resultado.
341
Por cuestiones de tamao de almacenamiento de la variable, los nmeros pueden ir desde el 1 hasta el 12, as que veamos que pasa si ingresamos 13.
342
En este caso, se ha producido un error, puesto que el tamao de la variable que utilizamos no fue lo suficientemente grande como para poder almacenar el valor del factorial. La imagen que vemos, es la de un ShortDump (Es decir, un error grave en la programacin). Esta ventana, nos indica porque se ha producido el error, cuando, en donde y hasta como podramos resolverlo. En esta caso, vamos a utilizar una pequea artimaa para que nuestro programa siga funcionando a pesar de este error, para ello, vamos a utilizar un comando llamado CATCH SYSTEMEXCEPTION. El cual funciona como un TRY-CATCH en Java o .NET, y lo que hace es simplemente intentar ejecutar una sentencia y si no puede, nos enva un error personalizado, que permite que el programa siga funcionando a pesar del error. Para esto, debemos hacer unas cuantas modificaciones al programa.
CLASS C_FACTORIAL DEFINITION. PUBLIC SECTION. CLASS-METHODS: MAIN. METHODS: SET_FACT IMPORTING NUM TYPE I, GET_RESULT RETURNING VALUE(FACT) TYPE I. PRIVATE SECTION. DATA: FACT TYPE I, FLAG TYPE C. ENDCLASS. "FACTORIAL DEFINITION
Declaramos una variable llamada FLAG que nos va a servir al momento de mostrar el mensaje de resultado.
343
METHOD SET_FACT. CLEAR FLAG. FACT = 1. IF NUM GT 0. DO NUM TIMES. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. FACT = FACT * SY-INDEX. ENDCATCH. IF SY-SUBRC EQ 5. FACT = 0. FLAG = 'X'. EXIT. ENDIF. ENDDO. ENDIF. ENDMETHOD. "SET_FACT
Dentro del mtodo SET_FACT, limpiamos nuestra variable FLAG y utilizamos un CATCH SYSTEM-EXCEPTIONS, en este caso el ARITHMETIC_ERRORS, que significa que cualquier error de tipo Overflow (valor ms grande que el tamao de variable), va a lanzar un SY-SUBRC igual a 5 en vez de una pantalla de ShortDump. En el caso de que el SY-SUBRC sea igual a 5, entonces limpiamos la variable FACT y llenamos con X la variable FLAG. Obviamente, salimos del mtodo utilizando la sentencia EXIT.
344
METHOD GET_RESULT. IF FLAG EQ SPACE. WRITE: 'El Factorial es: ', ME->FACT. ELSE. WRITE: 'Error, ingrese valores del 1 al 12'. ENDIF. ENDMETHOD. "GET_RESULT
En el mtodo GET_RESULT, preguntamos si la variable FLAG est vaca o tiene el valor X. Si est vaca, imprimimos el valor del factorial, si tiene el valor X, imprimimos un mensaje de advertencia.
Ahora, veamos el mismo ejemplo pero utilizando el Generador de Clases (SE24), gracias a lo cual podramos obtener el Factorial de un nmero desde cualquier programa.
345
346
Ambas variables tiene un Level (Nivel) 0 Instance Attribute (Atributo de Instacia), un Visibility (Visibilidad) 0 Private (Privado). Luego, nos dirigimos a la pestaa Methods (Mtodos).
Declaramos dos mtodos, SET_FACT y GET_RESULT, ambos con Nivel 0 Atributo de Instacia y Visibilidad 2 Public (Pblica). Para asignar los parmetros, debemos presionar el botn Parameters (Parmetros) .
347
GET_RESULT tiene el parmetro FACT de tipo RETURNING. Para poder asignarles cdigo a los mtodos, debemos posicionarnos sobre cada uno de ellos y presionar el botn Code .
348
method SET_FACT. CLEAR FLAG. FACT = 1. IF NUM GT 0. DO NUM TIMES. CATCH SYSTEM-EXCEPTIONS ARITHMETIC_ERRORS = 5. FACT = FACT * SY-INDEX. ENDCATCH. IF SY-SUBRC EQ 5. FACT = 0. FLAG = 'X'. EXIT. ENDIF. ENDDO. ENDIF. endmethod.
method GET_RESULT. IF FLAG EQ SPACE. WRITE: 'El Factorial es: ', ME->FACT. ELSE. WRITE: 'Error, ingrese valores del 1 al 12'. ENDIF. endmethod.
Con esto, solo nos queda grabar, activar. La clase est lista para ser utilizada, pero claro, lo mejor es probarlo antes. Para esto, presionamos el botn Test o presionamos F8 .
349
Como sabemos que SET_FACT es el mtodo que recibe el valor ingreado por el usario, lo ejecutamos presionando el botn Execute Method (Ejecutar Mtodo) .
350
A pesar de que el valor de FACT aparece como 0, simplemente debemos retroceder para ver el resultado.
REPORT ZDUMMY_PRIMER_PROGRAMA. SELECTION-SCREEN BEGIN OF SCREEN 101 AS WINDOW. PARAMETERS NUMBER TYPE I. SELECTION-SCREEN END OF SCREEN 101.
351
START-OF-SELECTION. CALL SELECTION-SCREEN '101' STARTING AT 10 10. IF SY-SUBRC NE 0. EXIT. ENDIF. DATA MY_OBJ TYPE REF TO ZFACTORIAL. CREATE OBJECT MY_OBJ. CALL METHOD MY_OBJ->SET_FACT( EXPORTING NUM = NUMBER ). CALL METHOD MY_OBJ->GET_RESULT.
Ejecutamos y veremos que el resultado es el mismo, aunque el cdigo es mucho ms corto y reutilizable.
352
*=====================================================* * 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. *=====================================================* * 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. * *=====================================================* * *=====================================================*
353
*=====================================================* * 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. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_DATOS. PERFORM FILL_LAYOUT. PERFORM FILL_CATALOG. PERFORM LLAMAR_ALV. CALL SCREEN 0100. *&----------------------------------------------------* *& 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 * *=====================================================* * *=====================================================*
354
*&----------------------------------------------------* *& Form fill_layout * *&----------------------------------------------------* FORM FILL_LAYOUT. GS_LAYOUT-SEL_MODE = 'A'. ENDFORM. " fill_layout
*&----------------------------------------------------* *& 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'. GS_FIELDCAT-REPTEXT = 'Nombre Programa'. GS_FIELDCAT-COL_POS = 2. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT.
355
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 = 'Conexin con SAP'. GS_FIELDCAT-COL_POS = 5. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT. ENDFORM. " fill_catalog
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.
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 cdigo 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
*=====================================================* * 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. * *=====================================================*
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 catlogo de campos, GT_SORT donde se indican los criterios de ordenacin 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 PERFORMs, el primero carga los datos, el segundo determina el formato del ALV, el tercero llena el catlogo 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
*&----------------------------------------------------* *& Form fill_layout * *&----------------------------------------------------* FORM FILL_LAYOUT. GS_LAYOUT-SEL_MODE = 'A'. ENDFORM. " fill_layout
*&----------------------------------------------------* *& 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 = 'Conexin con SAP'. GS_FIELDCAT-COL_POS = 5. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT. ENDFORM. " fill_catalog
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
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 mtodo SET_TABLE_FOR_FIRST_DISPLAY pasndole los parmetros correspondientes. Llamamos al mtodo SET_READY_FOR_INPUT pasando 0 como parmetro, 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
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
366
Debemos llamar a la clase LCL_EVENT_RECIEVER, pero al mismo tiempo debemos modificar su estructura (Solamente dentro de nuestro programa, claro est...)
Agregamos un nuevo campos a nuestro TYPE TY_PROGRAMAS y creamos un nuevo TYPE llamado TY_NOMBRE.
*=====================================================* * 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, * *=====================================================*
367
ENTORNO TYPE ZLENGUAJES_PROG-ENTORNO, CONEX_SAP TYPE ZLENGUAJES_PROG-CONEX_SAP, ID TYPE ZPROGRAMAS-ID, END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_NOMBRE, ID TYPE ZLENGUAJES_PROG-ID, NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE, END OF TY_NOMBRE.
368
LT_F4 nos sirve para determinar que campos van a tener asignada una ayuda de bsqueda. RETURN_TAB es la tabla que nos devuelve el valor seleccionado por la funcin para crear ayudas de bsqueda. T_STABLE nos permite que el ALV mantenga su posicin al momento de actualizar los datos. Agregamos algunas variables.
*=====================================================* * 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, EVENT_RECEIVER TYPE REF TO LCL_EVENT_RECEIVER, X_SAVE, W_ERROR TYPE C, L_VALID(1) TYPE C. * *=====================================================*
EVENT_RECIEVER nos permite crear una referencia para llamar eventos en el ALV. W_ERROR nos indica si hay algn error en la modificacin de datos. L_VALID indica si la operacin es vlida o no.
369
*=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_NOMBRE> LIKE LINE OF T_NOMBRE, <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS. * *=====================================================*
*-----------------------------------------------------* * CLASS LCL_EVENT_RECEIVER DEFINITION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER DEFINITION. PUBLIC SECTION. METHODS: HANDLE_DATA_CHANGED FOR EVENT DATA_CHANGED OF CL_GUI_ALV_GRID IMPORTING ER_DATA_CHANGED, HANDLE_F4_HELP FOR EVENT ONF4 OF CL_GUI_ALV_GRID IMPORTING E_FIELDNAME ES_ROW_NO ER_EVENT_DATA. ENDCLASS. "LCL_EVENT_RECEIVER DEFINITION
Definimos dos mtodos, HANDLE_DATA_CHANGED (Que valida si algn campo ha cambiado su valor) y HANDLE_F4_HELP que sirve para asignar las ayudas de bsqueda dinmicas.
370
*-----------------------------------------------------* * CLASS lcl_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_EVENT_RECEIVER IMPLEMENTATION. METHOD HANDLE_DATA_CHANGED. PERFORM DATA_CHANGED USING ER_DATA_CHANGED. ENDMETHOD. METHOD HANDLE_F4_HELP. PERFORM HANDLE_ONF4 USING E_FIELDNAME ES_ROW_NO. ER_EVENT_DATA->M_EVENT_HANDLED = 'X'. ENDMETHOD. ENDCLASS. "HANDLE_F4_HELP "LCL_EVENT_RECEIVER IMPLEMENTATION "HANDLE_DATA_CHANGED
Dentro del mtodo HANDLE_DATA_CHANGED llamamos al FORM DATA_CHANGED. Dentro del mtodo HANDLE_F4_HELP llamamos al FORM HANDEL_ONF4. ER_EVENT_DATA->M_EVENT_HANDLED especificamos que queremos activar el evento. = X,
*&----------------------------------------------------* *& 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 ).
371
SELECT ID NOMBRE INTO TABLE T_NOMBRE FROM ZLENGUAJES_PROG. ENDFORM. " cargar_datos
Agregamos un nuevo select, esta vez a ZLENGUAJES_PROG para poder obtener los valores necesarios para nuestra ayuda de bsqueda dinmica.
CLEAR GS_FIELDCAT. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-FIELDNAME = 'NOMBRE'. GS_FIELDCAT-EDIT = 'X'. GS_FIELDCAT-F4AVAILABL = 'X'. GS_FIELDCAT-REPTEXT = 'Nombre Lenguaje'. GS_FIELDCAT-COL_POS = 3. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT.
Dentro del catlogo, solamente vamos a modificar un campo, por lo que agregamos EDIT para que pueda modificarse y F4AVAILABL para que acepte la ayuda de bsqueda dinmica.
372
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. CREATE OBJECT EVENT_RECEIVER. LT_F4-FIELDNAME = 'NOMBRE'. LT_F4-REGISTER = 'X' . LT_F4-GETBEFORE = 'X' . LT_F4-CHNGEAFTER = 'X' . APPEND LT_F4. SET HANDLER EVENT_RECEIVER>HANDLE_DATA_CHANGED FOR GRID1. SET HANDLER EVENT_RECEIVER->HANDLE_F4_HELP FOR GRID1. CALL METHOD GRID1->REGISTER_F4_FOR_FIELDS EXPORTING IT_F4 = LT_F4[]. = 1 = 2 = 3 = 4 = MYCONTAINER
LIFETIME_DYNPRO_DYNPRO_LINK = 5.
373
IF SY-BATCH IS INITIAL. CALL METHOD GRID1->REGISTER_EDIT_EVENT EXPORTING I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED. ENDIF. 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
Creamos el objeto EVENT_RECIEVER para poder asignar los eventos al ALV. Llenamos la tabla LT_F4, con el campo que tendr la ayuda de bsqueda dinmica. Establecemos los eventos utilizando el comando SET HANDLER.
374
La variable SY-BATCH nos indica si estamos ejecutando el programa en fondo o en modo directo, si es en modo directo, entonces registramos el evento de modificacin.
*&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. DATA: OK_CODE TYPE SY-UCOMM. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'BACK' OR 'EXIT' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. WHEN 'SAVE'. CALL METHOD GRID1->CHECK_CHANGED_DATA IMPORTING E_VALID = L_VALID. IF L_VALID EQ 'X'. PERFORM GRABAR_DATOS. ENDIF. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
Agregamos el cdigo de funcin SAVE. 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. 375
*&----------------------------------------------------* *& Form data_changed * *&----------------------------------------------------* FORM DATA_CHANGED USING RR_DATA_CHANGED TYPE REF TO CL_ALV_CHANGED_DATA_PROTOCOL. DATA: W_NEW, LS_MOD_CELLS TYPE LVC_S_MODI, LS_CELLS TYPE LVC_S_MODI. DATA: L_NOMBRE TYPE ZLENGUAJES_PROG-NOMBRE. LOOP AT RR_DATA_CHANGED->MT_GOOD_CELLS INTO LS_MOD_CELLS. CASE LS_MOD_CELLS-FIELDNAME. WHEN 'NOMBRE'. 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 algn nombre' = L_NOMBRE. IF L_NOMBRE IS INITIAL. = LS_MOD_CELLS-ROW_ID I_FIELDNAME = LS_MOD_CELLS-FIELDNAME
I_FIELDNAME = LS_MOD_CELLS-FIELDNAME
376
= LS_MOD_CELLS-ROW_ID.
READ TABLE T_NOMBRE WITH KEY NOMBRE = L_NOMBRE ASSIGNING <FS_NOMBRE>. IF SY-SUBRC NE 0. CALL METHOD RR_DATA_CHANGED->ADD_PROTOCOL_ENTRY EXPORTING I_MSGID I_MSGNO I_MSGTY I_MSGV1 I_ROW_ID ELSE. CALL METHOD RR_DATA_CHANGED->MODIFY_CELL EXPORTING I_ROW_ID I_VALUE ENDIF. ENDIF. ENDCASE. ENDLOOP. ENDFORM. "data_changed = LS_MOD_CELLS-ROW_ID = <FS_NOMBRE>-ID. I_FIELDNAME = 'ID' = '0K' = '000' = 'E' = 'Nombre ingresado no existe' = LS_MOD_CELLS-ROW_ID.
Hacemos
un
LOOP
RR_DATA_CHANGED-
377
valor. Llamamos al mtodo GET_CELL_VALUE para validar el nuevo contenido del campo. Si est vaco, mostramos un mensaje de error con el mtodo ADD_PROTOCOL_ENTRY, en caso contrario leemos la tabla interna T_NOMBRE para validar que el valor exista. Si no hay ms problemas, llamamos al mtodo MODIFY_CELL para modificar el campo ID (Puesto que nosotros hemos modificado el campo NOMBRE, pero necesitamos que a su vez se modifique tambin el campo ID).
*&----------------------------------------------------* *& Form handle_onf4 * *&----------------------------------------------------* FORM HANDLE_ONF4 USING P_E_FIELDNAME P_ES_ROW_NO STRUCTURE LVC_S_ROID. CASE P_E_FIELDNAME. WHEN '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
IF NOT RETURN_TAB[] IS INITIAL. READ TABLE RETURN_TAB INDEX 1. READ TABLE T_PROGRAMAS INDEX P_ES_ROW_NO-ROW_ID ASSIGNING <FS_PROGRAMAS>. READ TABLE T_NOMBRE WITH KEY NOMBRE = RETURN_TAB-FIELDVAL ASSIGNING <FS_NOMBRE>. <FS_PROGRAMAS>-NOMBRE = RETURN_TAB-FIELDVAL. <FS_PROGRAMAS>-ID = <FS_NOMBRE>-ID. CALL METHOD GRID1->REFRESH_TABLE_DISPLAY EXPORTING IS_STABLE = T_STABLE. ENDIF. ENDCASE. ENDFORM. "handle_onf4
Llamamos al mtodo F4IF_INT_TABLE_VALUE_REQUEST para poder mostrar la ayuda de bsqueda dinmica. Llamamos al mtodo REFRESH_TABLE_DISPLAY para refrescar el contenido del ALV.
*&----------------------------------------------------* *& Form grabar_datos * *&----------------------------------------------------* FORM GRABAR_DATOS. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE ID NE SPACE. UPDATE ZPROGRAMAS SET ID = <FS_PROGRAMAS>-ID WHERE ID_PROG EQ <FS_PROGRAMAS>-ID_PROG.
379
IF SY-SUBRC EQ 0. COMMIT WORK. ELSE. ROLLBACK WORK. ENDIF. ENDLOOP. ENDFORM. " GRABAR_DATOS
Recorremos todos los registros de nuestra tabla interna, que tengan un valor en el campo ID, luego utilizamos un UPDATE para actualizar los valores de la Base de Datos. Grabamos, activamos y ejecutamos.
380
REPORT ZDUMMY_PRIMER_PROGRAMA. *=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG, ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO, END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_HEADER, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, END OF TY_HEADER. * *=====================================================*
381
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE, T_HEADER TYPE STANDARD TABLE OF TY_HEADER, GT_FIELDCAT_TREE TYPE LVC_T_FCAT. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE, G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, L_HIERARCHY_HEADER TYPE TREEV_HHDR. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS, <FS_HEADER> LIKE LINE OF T_HEADER, <FS_TREE> LIKE LINE OF T_PROGRAMAS. * *=====================================================* * *=====================================================* * *=====================================================*
382
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_DATOS. PERFORM INIT_TREE. CALL SCREEN 0100. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE. ENDLOOP. SORT T_HEADER. DELETE ADJACENT DUPLICATES FROM T_HEADER. ENDFORM. " CARGAR_DATOS * *=====================================================*
383
*&----------------------------------------------------* *& 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. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
384
*&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. DATA: L_TREE_CONTAINER_NAME(30) TYPE C. L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 =
LIFETIME_DYNPRO_DYNPRO_LINK = 5. 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
= 4 = 6 = 7.
ILLEGAL_NODE_SELECTION_MODE = 5
PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER. 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.
*&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. CLEAR GS_FIELDCAT. GS_FIELDCAT-COL_POS = 1. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. GS_FIELDCAT-SCRTEXT_S = 'Nom. Programa'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-OUTPUTLEN = 20.
386
APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. CLEAR GS_FIELDCAT. GS_FIELDCAT-COL_POS = 2. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. ENDFORM. "fill_catalog_tree
*&----------------------------------------------------* * FORM build_hierarchy_header * *&----------------------------------------------------* FORM BUILD_HIERARCHY_HEADER CHANGING P_HIERARCHY_HEADER TYPE TREEV_HHDR. CLEAR P_HIERARCHY_HEADER. P_HIERARCHY_HEADER-HEADING = 'Cdigo'(300). P_HIERARCHY_HEADER-WIDTH = 60. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. ENDFORM. "BUILD_HIERARCHY_HEADER
*&----------------------------------------------------* *& Form create_hierarchy * *&----------------------------------------------------* FORM CREATE_HIERARCHY. DATA: L_ROOT_KEY TYPE LVC_NKEY, L_NEXT_KEY TYPE LVC_NKEY,
387
L_LAST_KEY TYPE LVC_NKEY, HEADER TYPE STRING, W_MENGE_TEXT(13) TYPE C. CLEAR L_ROOT_KEY.
LOOP AT T_HEADER ASSIGNING <FS_HEADER>. HEADER = <FS_HEADER>-LENGUAJE. CLEAR L_ROOT_KEY. CLEAR L_NEXT_KEY. PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. ENDLOOP. ENDLOOP. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. ENDFORM. "CREATE_HIERARCHY
*&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY.
388
DATA: L_NODE_TEXT TYPE LVC_VALUE, 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 ENDFORM. = L_NEXT_KEY. "ADD_NODE = = L_NODE_TEXT = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME.
*&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. 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. = = T_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
389
ENDFORM.
"ADD_LEAF
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG, ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO, END OF TY_PROGRAMAS. TYPES: BEGIN OF TY_HEADER, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, END OF TY_HEADER. * *=====================================================*
Declaramos dos TYPEs, 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.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_TREE TYPE STANDARD TABLE OF TY_PROGRAMAS WITH HEADER LINE, T_HEADER TYPE STANDARD TABLE OF * *=====================================================*
390
Declaramos algunas tablas internas, T_PROGRAMAS que guarda los datos del ALV, T_TREE que es una tabla intermedia para mostrar los datos del ALV, T_HEADER es la cabecera del ALV, GT_FIELDCAT_TREE es el catlogo del ALV.
*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE, G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, L_HIERARCHY_HEADER TYPE TREEV_HHDR. * *=====================================================*
Declaramos algunas variables. OK_CODE para guardar el cdigo de funcin, G_ALV_TREE que es un objeto de la clase CL_GUI_ALV_TREE, G_CUSTOM_CONTAINER que es un contenedor para el ALV y L_HIERARCHY_HEADER que sirve para definir la cabecera.
*=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_PROGRAMAS> LIKE LINE OF T_PROGRAMAS, <FS_HEADER> LIKE LINE OF * *=====================================================*
391
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_DATOS. PERFORM INIT_TREE. CALL SCREEN 0100. * *=====================================================*
*&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. SELECT LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS>. APPEND INITIAL LINE TO T_HEADER ASSIGNING <FS_HEADER>. <FS_HEADER>-LENGUAJE = <FS_PROGRAMAS>-LENGUAJE.
392
ENDLOOP. SORT T_HEADER. DELETE ADJACENT DUPLICATES FROM T_HEADER. ENDFORM. " CARGAR_DATOS
Seleccionamos los datos de la vista ZVLENGUAJES_PROG. Luego asignamos el campo LENGUAJE a la tabla T_HEADER y eliminamos los registros duplicados.
*&----------------------------------------------------* *& 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. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM.
393
CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
*&----------------------------------------------------* *& Form INIT_TREE * *&----------------------------------------------------* FORM INIT_TREE. DATA: L_TREE_CONTAINER_NAME(30) TYPE C. L_TREE_CONTAINER_NAME = 'CUSTOM_ALV'. CREATE OBJECT G_CUSTOM_CONTAINER EXPORTING CONTAINER_NAME L_TREE_CONTAINER_NAME EXCEPTIONS CNTL_ERROR CNTL_SYSTEM_ERROR CREATE_ERROR LIFETIME_ERROR = 1 = 2 = 3 = 4 =
394
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. PERFORM BUILD_HIERARCHY_HEADER CHANGING L_HIERARCHY_HEADER. 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. = 1 = 2 = 3 = 4 = 6 = 7. = G_CUSTOM_CONTAINER = = '' = 'X' = ''
CL_GUI_COLUMN_TREE=>NODE_SEL_MODE_SINGLE
ILLEGAL_NODE_SELECTION_MODE = 5
395
Creamos el contenedor G_CUSTOM_CONTAINER pasando como parmetro el nombre de nuestro CUSTOM_CONTROL contenido en la variable L_TREE_CONTAINER_NAME. Creamos el objeto G_ALV_TREE asignndolo a nuestro contenedor G_CUSTOM_CONTAINER. Llammos al FORM FILL_CATALOG_TREE donde llenaremos el catlogo del ALV. Llammos al FORM BUILD_HIERARCHY_HEADER, donde establecemos los detalles de la cabecera. Llammos al mtodo SET_TABLE_FOR_FIRST_DISPLAY para llamar al ALV. Finalmemte llammos al FORM CREATE_HIERARCHY, donde creamos la estructura del ALV.
*&----------------------------------------------------* *& Form fill_catalog_tree * *&----------------------------------------------------* FORM FILL_CATALOG_TREE. DATA: GS_FIELDCAT TYPE LVC_S_FCAT. CLEAR GS_FIELDCAT. GS_FIELDCAT-COL_POS = 1. GS_FIELDCAT-FIELDNAME = 'NOM_PROG'. GS_FIELDCAT-SCRTEXT_S = 'Nom. Programa'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-OUTPUTLEN = 20. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE.
396
CLEAR GS_FIELDCAT. GS_FIELDCAT-COL_POS = 2. GS_FIELDCAT-FIELDNAME = 'ENTORNO'. GS_FIELDCAT-SCRTEXT_S = 'Entorno'. GS_FIELDCAT-TABNAME = 'T_PROGRAMAS'. GS_FIELDCAT-OUTPUTLEN = 15. APPEND GS_FIELDCAT TO GT_FIELDCAT_TREE. ENDFORM. "fill_catalog_tree
*&----------------------------------------------------* * FORM build_hierarchy_header * *&----------------------------------------------------* FORM BUILD_HIERARCHY_HEADER CHANGING P_HIERARCHY_HEADER TYPE TREEV_HHDR. CLEAR P_HIERARCHY_HEADER. P_HIERARCHY_HEADER-HEADING = 'Cdigo'(300). P_HIERARCHY_HEADER-WIDTH = 60. P_HIERARCHY_HEADER-WIDTH_PIX = ' '. ENDFORM. "BUILD_HIERARCHY_HEADER
397
*&----------------------------------------------------* FORM CREATE_HIERARCHY. DATA: L_ROOT_KEY TYPE LVC_NKEY, L_NEXT_KEY TYPE LVC_NKEY, L_LAST_KEY TYPE LVC_NKEY, HEADER TYPE STRING, W_MENGE_TEXT(13) TYPE C. CLEAR L_ROOT_KEY. LOOP AT T_HEADER ASSIGNING <FS_HEADER>. HEADER = <FS_HEADER>-LENGUAJE. CLEAR L_ROOT_KEY. CLEAR L_NEXT_KEY. PERFORM ADD_NODE USING HEADER L_ROOT_KEY CHANGING L_NEXT_KEY. LOOP AT T_PROGRAMAS ASSIGNING <FS_PROGRAMAS> WHERE LENGUAJE EQ <FS_HEADER>-LENGUAJE. MOVE-CORRESPONDING <FS_PROGRAMAS> TO T_TREE. PERFORM ADD_LEAF USING T_TREE L_NEXT_KEY CHANGING L_LAST_KEY. ENDLOOP. ENDLOOP. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE. ENDFORM. "CREATE_HIERARCHY
398
Recorremos los registros de la tabla T_HEADER, 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. Luego recorremos todos los registros de la tabla T_PROGRAMAS buscando los registros que tengan el campo LENGUAJE igual que el nodo, esto para poder agregarlos utilizando el FORM ADD_LEAF. Una vez que terminamos llammos al mtodo FRONTEND_UPDATE para refrescar los valores del ALV.
*&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. DATA: L_NODE_TEXT TYPE LVC_VALUE, 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. = = L_NODE_TEXT = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME.
399
ENDFORM.
"ADD_NODE
Llammos al mtodo ADD_NODE para crear un nuevo nodo. Aunque claro, pasamos otro parmetro para que se cree como subnodo. Grabamos, activamos y ejecutamos.
400
*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, G_ALV_TREE TYPE REF TO CL_GUI_ALV_TREE, G_CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, L_HIERARCHY_HEADER TYPE TREEV_HHDR, G_LINE_BEHAVIOUR TYPE REF TO CL_DRAGDROP, G_FAV_BEHAVIOUR TYPE REF TO CL_DRAGDROP, L_LAST_KEY TYPE LVC_NKEY, W_NODE_KEY TYPE LVC_NKEY. * *=====================================================*
401
Agregamos algunas variables, G_LINE_BEHAVIOUR objeto que determina que el nodo puede moverse. G_FAV_BEHAVIOUR objeto que determina que el folder puede aceptar un nuevo nodo. L_LAST_KEY determina el nodo padre. W_NODE_KEY variable para almacenar el nodo que se ha movido de carpeta.
*-----------------------------------------------------* * CLASS LCL_DRAGDROPOBJ DEFINITION * *-----------------------------------------------------* CLASS LCL_DRAGDROPOBJ DEFINITION. PUBLIC SECTION. DATA: CPS_PROGRAMAS TYPE TY_PROGRAMAS, CP_NODE_TEXT TYPE LVC_VALUE, CP_NODE_KEY TYPE LVC_NKEY. ENDCLASS. "LCL_DRAGDROPOBJ DEFINITION
Definimos algunas variables de clase. CPS_PROGRAMAS sirve como una cabecera con los datos de los nodos. CP_NODE_TEXT almacena el texto del nodo y CP_NODE_KEY almacena el ndice del nodo.
*-----------------------------------------------------* * CLASS lcl_dnd_event_receiver DEFINITION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER DEFINITION. PUBLIC SECTION. METHODS:
402
HANDLE_LINE_DRAG FOR EVENT ON_DRAG OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY FIELDNAME DRAG_DROP_OBJECT, HANDLE_FAV_DROP FOR EVENT ON_DROP OF CL_GUI_ALV_TREE IMPORTING SENDER NODE_KEY DRAG_DROP_OBJECT. ENDCLASS. "lcl_dnd_event_receiver DEFINITION
Declaramos dos mtodos para manejar el Drag & Drop (Arrastrar y soltar) en el ALV.
*-----------------------------------------------------* * CLASS lcl_dnd_event_receiver IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_DND_EVENT_RECEIVER IMPLEMENTATION. METHOD HANDLE_LINE_DRAG. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ. CREATE OBJECT DATAOBJ. DATAOBJ->CP_NODE_KEY = NODE_KEY. CALL METHOD SENDER->GET_OUTTAB_LINE EXPORTING I_NODE_KEY IMPORTING E_OUTTAB_LINE = DATAOBJ->CPS_PROGRAMAS E_NODE_TEXT = DATAOBJ->CP_NODE_TEXT. = NODE_KEY
403
DRAG_DROP_OBJECT->OBJECT = DATAOBJ. ENDMETHOD. METHOD HANDLE_FAV_DROP. DATA: DATAOBJ TYPE REF TO LCL_DRAGDROPOBJ, L_NEW_KEY TYPE LVC_NKEY. CATCH SYSTEM-EXCEPTIONS MOVE_CAST_ERROR = 1. DATAOBJ ?= DRAG_DROP_OBJECT->OBJECT. W_NODE_KEY = DATAOBJ->CP_NODE_KEY. PERFORM ADD_LEAF USING DATAOBJ->CPS_PROGRAMAS NODE_KEY CHANGING DATAOBJ->CP_NODE_KEY. CALL METHOD G_ALV_TREE->DELETE_SUBTREE EXPORTING I_NODE_KEY = W_NODE_KEY. CALL METHOD SENDER->FRONTEND_UPDATE. ENDCATCH. IF SY-SUBRC <> 0. CALL METHOD DRAG_DROP_OBJECT->ABORT. ENDIF. ENDMETHOD. ENDCLASS. "HANDLE_FAV_DROP "lcl_dnd_event_receiver IMPLEMENTATION "HANDLE_LINE_DRAG
En el mtodo HANDLE_LINE_DRAG, creamos un objeto DATAOBJ y le asignamos el contenido del nodo. Con el mtodo GET_OUTTAB_LINE llenamos las variables 404
CPS_PROGRAMAS y CP_NODE_TEXT con los valores correspondientes al nodo. Asignamos el nodo al evento de Drag & Drop. En el mtodo HANDLE_FAV_DROP, hacemos un CATCH SYSTEM-EXCEPTION por si hay algn problema al mover el nodo de una carpeta a otra. 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 FORM ADD_LEAF con el nodo que hemos movido de una carpeta a otra. Llamamos al mtodo DELETE_SUBTREE con el valor de la variable W_NODE_KEY para poder eliminar al nodo de su posicin original. Llamamos al mtodo FRONTEND_UPDATE para actualizar el ALV.
PERFORM DEFINE_DND_BEHAVIOUR.
DATA: LT_EVENTS TYPE CNTL_SIMPLE_EVENTS, L_EVENT TYPE CNTL_SIMPLE_EVENT, L_DND_EVENT_RECEIVER TYPE REF TO LCL_DND_EVENT_RECEIVER. CALL METHOD G_ALV_TREE->GET_REGISTERED_EVENTS IMPORTING EVENTS = LT_EVENTS. CALL METHOD G_ALV_TREE->SET_REGISTERED_EVENTS
405
ILLEGAL_EVENT_COMBINATION = 3. CREATE OBJECT L_DND_EVENT_RECEIVER. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_FAV_DROP FOR G_ALV_TREE. SET HANDLER L_DND_EVENT_RECEIVER->HANDLE_LINE_DRAG FOR G_ALV_TREE. CALL METHOD G_ALV_TREE->FRONTEND_UPDATE.
Al final de INIT_TREE, agregamos este cdigo. El FORM DEFINE_DND_BEHAVIOUR determina el tipo de Drag & Drop que se utilizar tanto para los nodos como para las carpetas. Las tablas internas LT_EVENTS, L_EVENT, y ello, utilizamos los mtodos y Adems, establecemos los L_DND_EVENT_RECIEVER utilizar los eventos. Para
406
*&----------------------------------------------------* * FORM ADD_NODE * *&----------------------------------------------------* FORM ADD_NODE USING L_NAME L_ROOT_KEY CHANGING L_NEXT_KEY. DATA: L_NODE_TEXT TYPE LVC_VALUE, LS_TREE TYPE TY_PROGRAMAS, L_LAYOUT_NODE TYPE LVC_S_LAYN, L_HANDLE_FAVOURITE_FOLDER TYPE I. CALL METHOD G_FAV_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_FAVOURITE_FOLDER. L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_FAVOURITE_FOLDER. L_LAYOUT_NODE-ISFOLDER = 'X'. 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. = = L_NODE_TEXT = L_LAYOUT_NODE = LS_TREE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD L_NAME. CALL METHOD G_ALV_TREE->ADD_NODE
407
ENDFORM.
"ADD_NODE
Modificamos un poco el FORM ADD_NODE. Las variables L_LAYOUT y L_HANDLE_FAVOURITE_FOLDER, nos van a ayudar para establecer que los nodos son carpetas, y que pueden aceptar un subnodo dentro de ellas. Utilizamos el mtodo GET_HANDLE para obtener el manejador que nos permita asignar un ID al nodo. Pasamos el valor de la hacia el variable campo L_HANDLE_FAVOURITE_FOLDER
DRAGDROPID de la variable L_LAYOUT_NODE, adems, asignamos el valor X al campo ISFOLDER de la misma variable. Debemos pasar el parmetro IS_NODE_LAYOUT al mtodo ADD_NODE.
*&----------------------------------------------------* * FORM ADD_LEAF * *&----------------------------------------------------* FORM ADD_LEAF USING L_TREE TYPE TY_PROGRAMAS L_NEXT_KEY CHANGING L_LAST_KEY. DATA: L_LAYOUT_NODE TYPE LVC_S_LAYN, L_HANDLE_LINE TYPE I. CALL METHOD G_LINE_BEHAVIOUR->GET_HANDLE IMPORTING HANDLE = L_HANDLE_LINE.
408
L_LAYOUT_NODE-DRAGDROPID = L_HANDLE_LINE. 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_LAST_KEY. "ADD_LEAF = = L_TREE = L_LAYOUT_NODE CL_GUI_COLUMN_TREE=>RELAT_LAST_CHILD
Modificamos un poco el FORM ADD_LEAF. 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. Utilizando el mtodo GET_HANDLE asignamos un manejador a la variable L_LAYOUT_NODE-DRAGDROPID. Pasamos el parmetro IS_NODE_LAYOUT al mtodo ADD_NODE.
*&----------------------------------------------------* *& Form DEFINE_DND_BEHAVIOUR **&---------------------------------------------------* FORM DEFINE_DND_BEHAVIOUR. DATA: EFFECT TYPE I. CREATE OBJECT G_LINE_BEHAVIOUR. EFFECT = CL_DRAGDROP=>COPY. CALL METHOD G_LINE_BEHAVIOUR->ADD
409
CREATE OBJECT G_FAV_BEHAVIOUR. EFFECT = CL_DRAGDROP=>COPY. CALL METHOD G_FAV_BEHAVIOUR->ADD EXPORTING FLAVOR DRAGSRC EFFECT ENDFORM. = 'X' = ' ' = EFFECT. " DEFINE_DND_BEHAVIOUR "#EC NOTEXT
DROPTARGET = 'X'
Creamos
dos
objetos
G_LINE_BEHAVIOUR
G_FAV_BEHAVIOUR. Con cada uno de ellos, llamaremos al mtodo ADD, determinando cual se puede arrastrar y en donde se puede soltar. Es decir, cual funciona como objeto y cual como contenedor.
410
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, * *=====================================================*
411
NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG, ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO, END OF TY_PROGRAMAS. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_TABLE TYPE REF TO CL_SALV_TABLE, T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS, T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS, LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE, LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. * *=====================================================*
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_DATOS. PERFORM LLAMAR_ALV. *&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG. * *=====================================================*
412
ENDFORM.
" CARGAR_DATOS
*&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE CHANGING T_TABLE CATCH CX_SALV_MSG . ENDTRY. LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Id' ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Programa' ). T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). T_FUNCTIONS->SET_ALL( ABAP_TRUE ). T_DSPSET = T_TABLE->GET_DISPLAY_SETTINGS( ). T_DSPSET->SET_LIST_HEADER( 'Programas' ). = T_PROGRAMAS ). = T_TABLE
413
Como se darn cuenta, es un cdigo bastante pequeo, pero de todos modos vamos a revisarlo un poco.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_PROGRAMAS, ID_PROG TYPE ZVLENGUAJES_PROG-ID_PROG, LENGUAJE TYPE ZVLENGUAJES_PROG-LENGUAJE, NOM_PROG TYPE ZVLENGUAJES_PROG-NOM_PROG, ENTORNO TYPE ZVLENGUAJES_PROG-ENTORNO, END OF TY_PROGRAMAS. * *=====================================================*
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_TABLE TYPE REF TO CL_SALV_TABLE, T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS, T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS, LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE, LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE. * *=====================================================*
414
Declaramos varias tablas internas, T_PROGRAMAS que guardar los datos que obtengamos de la vista. T_TABLE es un parmetro para el mtodo FACTORY y sirve para crear la estructura del ALV. T_FUNCTIONS sirve para asignar las funciones de la barra de mens del ALV. T_DSPSET nos sirve para las opciones de visualizacin. LR_COLUMN nos permite tomar las caractersticas de una columna del ALV. LV_SALV_COLUMNS_TABLE nos permite tomar todas las columnas de ALV.
Tenemos dos FORMs CARGAR_DATOS (Donde cargamos los datos) y LLAMAR_ALV (Donde llamamos al ALV)...Bastante obvio no?
*&----------------------------------------------------* *& Form CARGAR_DATOS * *&----------------------------------------------------* FORM CARGAR_DATOS. SELECT ID_PROG LENGUAJE NOM_PROG ENTORNO INTO TABLE T_PROGRAMAS FROM ZVLENGUAJES_PROG.
415
ENDFORM.
" CARGAR_DATOS
Seleccionamos
todos
los
campos
de
la
vista
ZVLENGUAJES_PROG.
*&----------------------------------------------------* *& Form LLAMAR_ALV * *&----------------------------------------------------* FORM LLAMAR_ALV. TRY. CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE CHANGING T_TABLE CATCH CX_SALV_MSG . ENDTRY. LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'ID_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Id' ). LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ). LR_COLUMN ?= LV_SALV_COLUMNS_TABLE->GET_COLUMN( 'NOM_PROG' ). LR_COLUMN->SET_LONG_TEXT( 'Programa' ). T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ). T_FUNCTIONS->SET_ALL( ABAP_TRUE ). = T_PROGRAMAS ). = T_TABLE
416
Llammos
al
mtodo
esttico
FACTORY
de
la
clase
CL_SALV_TABLE, pasando dos nicos parmetros, T_TABLE que contendr la estructura del ALV y T_PROGRAMAS, que tiene los registros obtenidos de la vista. Utilizando
LV_SALV_COLUMNS_TABLE = T_TABLE->GET_COLUMNS( ).
Establecemos cual es texto de la columna. Porque hacemos esto? Pues muy simple, tanto ID_PROG como NOM_PROG no tienen asignado un elemento de datos, por lo tanto, el ALV no puede determinar cual es el texto que le corresponde, as que nos toca a nosotros asignarlo. Continuando, utilizamos
T_FUNCTIONS = T_TABLE->GET_FUNCTIONS( ).
417
418
*-----------------------------------------------------* * CLASS lcl_handle_events DEFINITION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS DEFINITION. PUBLIC SECTION. METHODS: ON_DOUBLE_CLICK FOR EVENT DOUBLE_CLICK OF CL_SALV_EVENTS_TABLE IMPORTING ROW COLUMN. ENDCLASS. "lcl_handle_events DEFINITION
*-----------------------------------------------------* * CLASS lcl_handle_events IMPLEMENTATION * *-----------------------------------------------------* CLASS LCL_HANDLE_EVENTS IMPLEMENTATION. METHOD ON_DOUBLE_CLICK. PERFORM MOSTRAR_DETALLE USING ROW COLUMN. ENDMETHOD. ENDCLASS. "on_double_click "lcl_handle_events IMPLEMENTATION
Implementamos
el
mtodo
llamado
al
FORM
MOSTRAR_DETALLE.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_PROGRAMAS TYPE STANDARD TABLE OF TY_PROGRAMAS, T_TABLE TYPE REF TO CL_SALV_TABLE, * *=====================================================*
419
T_FUNCTIONS TYPE REF TO CL_SALV_FUNCTIONS, T_DSPSET TYPE REF TO CL_SALV_DISPLAY_SETTINGS, LR_COLUMN TYPE REF TO CL_SALV_COLUMN_TABLE, LV_SALV_COLUMNS_TABLE TYPE REF TO CL_SALV_COLUMNS_TABLE, GR_EVENTS TYPE REF TO LCL_HANDLE_EVENTS.
Declaramos un Field-Symbol.
Dentro
de
LLAMAR_ALV,
agregamos
el
FORM
420
*-----------------------------------------------------* *& Form mostrar_detalle * *-----------------------------------------------------* FORM MOSTRAR_DETALLE USING P_ROW P_COLUMN. DATA: MENSAJE TYPE SHKONTEXT-MELDUNG. IF P_COLUMN EQ 'NOM_PROG'. READ TABLE T_PROGRAMAS INDEX P_ROW ASSIGNING <FS_PROGRAMAS>. CONCATENATE <FS_PROGRAMAS>-ID_PROG <FS_PROGRAMAS>-NOM_PROG <FS_PROGRAMAS>-LENGUAJE <FS_PROGRAMAS>-ENTORNO INTO MENSAJE SEPARATED BY SPACE. CALL FUNCTION 'MESSAGE_TEXT_DISPLAY_WITH_PARA' EXPORTING TEXT = MENSAJE. ENDIF. ENDFORM. " mostrar_detalle
Si hemos hecho doble clic sobre un registro de la columna NOM_PROG, entonces leemos el registro, concatenamos los valores en un cadena y llamamos al mdulo de funciones MESSAGE_TEXT_DISPLAY_WITH_PARA para mostrar una ventana con los datos.
421
*&----------------------------------------------------* *& Form process_events * *&----------------------------------------------------* FORM PROCESS_EVENTS. DATA: LR_EVENTS TYPE REF TO CL_SALV_EVENTS_TABLE. LR_EVENTS = T_TABLE->GET_EVENT( ). CREATE OBJECT GR_EVENTS. SET HANDLER GR_EVENTS->ON_DOUBLE_CLICK FOR LR_EVENTS. ENDFORM. " process_events
Utilizando el mtodo esttico GET_EVENT, obtenemos el evento definido para nuestro ALV. Creamos el objeto GR_EVENTS y le asignamos el HANDLER ON_DOUBLE_CLICK, es decir, le decimos que reaccione ante el doble clic. Este sera el resultado del reporte.
422
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_GRAPHIC_TABLE, LINE(255) TYPE X, END OF TY_GRAPHIC_TABLE. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, URL(255) TYPE C, CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER, PICTURE TYPE REF TO CL_GUI_PICTURE, L_BYTECOUNT TYPE I, L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0, GRAPHIC_SIZE TYPE I. * *=====================================================* * *=====================================================* * *=====================================================*
423
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. CALL SCREEN 0100. *&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. PERFORM LOAD_IMAGE. ENDMODULE. " STATUS_0100 OUTPUT * *=====================================================*
*&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
424
*&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV', PICTURE EXPORTING PARENT = CONTAINER1. 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. = 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
TABLES BDS_BITMAP_FILE BITMAP_FILE EXCEPTIONS OTHERS CALL FUNCTION 'DP_CREATE_URL' EXPORTING TYPE TABLES DATA CHANGING URL = URL. = T_GRAPHIC_TABLE = 'IMAGE' SUBTYPE = 'BMP' = 1. = L_CONTENT = T_GRAPHIC_TABLE
CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. ENDFORM. " load_image
Revisemos el cdigo por partes. Es un cdigo sencillo y corto, as que ser fcil entenderlo.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_GRAPHIC_TABLE, LINE(255) TYPE X, END OF TY_GRAPHIC_TABLE. * *=====================================================*
426
Declaramos un TYPE llamado TY_GRAPHIC_TABLE que contiene un nico campo, llamado LINE de 255 caracteres y de tipo X. Esto es porque las imgenes de almacenan en formato hexadecimal.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_GRAPHIC_TABLE TYPE STANDARD TABLE OF TY_GRAPHIC_TABLE. * *=====================================================*
*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, URL(255) TYPE C, CONTAINER1 TYPE REF TO CL_GUI_CUSTOM_CONTAINER, PICTURE TYPE REF TO CL_GUI_PICTURE, L_BYTECOUNT TYPE I, L_CONTENT TYPE STANDARD TABLE OF BAPICONTEN INITIAL SIZE 0, GRAPHIC_SIZE TYPE I. * *=====================================================*
OK_CODE almacena el valor del cdigo de funcin. URL almacena una direccin donde se guarda la imagen en forma temporal.
427
CONTAINER1
contiene
el
nombre
de
nuestro
CUSTOM_CONTROL. PICTURE objeto que cargar y mostrar la imagen en el Dynpro. L_BYTECOUNT cuenta el nmero de bytes de la imagen que queremos visualizar. L_CONTENT almacena el contenido de la imagen. GRAPHIC_SIZE es el tamao de la imagen luego de convetirla a BMP.
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. PERFORM LOAD_IMAGE. ENDMODULE. " STATUS_0100 OUTPUT
428
Llamamos a la barra de mens y al ttulo del programa. Adems, en el FORM LOAD_IMAGE vamos a cargar la imagen en el Dynpro.
*&----------------------------------------------------* *& Form load_image * *&----------------------------------------------------* FORM LOAD_IMAGE. CREATE OBJECT: CONTAINER1 EXPORTING CONTAINER_NAME = 'CUSTOM_ALV', PICTURE EXPORTING PARENT = CONTAINER1. 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. = L_CONTENT = L_BYTECOUNT = 'GRAPHICS' = 'ENJOY' = 'BMAP' = 'BCOL'
429
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. = T_GRAPHIC_TABLE = 'IMAGE' SUBTYPE = 'BMP' = 1. = L_CONTENT = T_GRAPHIC_TABLE = GRAPHIC_SIZE
CALL METHOD PICTURE->LOAD_PICTURE_FROM_URL EXPORTING URL = URL. CALL METHOD PICTURE->SET_DISPLAY_MODE EXPORTING DISPLAY_MODE = PICTURE->DISPLAY_MODE_FIT_CENTER. ENDFORM. " load_image
Creamos los objetos CONTAINER1 (Asociado a nuestro CUSTOM_CONTROL) y PICTURE (Mostrar la imagen en el contenedor).
430
Llamamos a la funcin SAPSCRIPT_GET_GRAPHIC_BDS para obtener los datos de la imagen que queremos mostrar, que en este caso es ENJOY. Llamamos a la funcin SAPSCRIPT_CONVERT_BITMAP para convertir la imagen a un Bitmap. Llamamos a la funcin DP_CREATE_URL para generar una direccin donde se encuentra almacenada temporalmente la imagen BMP. Llamamos al mtodo LOAD_PICTURE_FROM_URL para cargar la imagen en memoria. Llamamos al mtodo SET_DISPLAY_MODE para mostrar la imagen.
431
Leer PDFs
Bueno, esto si que no creo que lo lleguen a necesitar alguna vez...Pero bueno, vale la pena conocerlo. Este es el cdigo.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_FILETAB TYPE FILETABLE. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER, CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, W_SUBRC TYPE SY-SUBRC, V_URL TYPE CHAR255. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. * *=====================================================* * *=====================================================* * *=====================================================*
432
SELECTION-SCREEN END OF BLOCK TEST. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CALL SCREEN 0100. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. = 'Seleccionar archivo' = '*.pdf' DEFAULT_FILENAME = '*.pdf' * *=====================================================*
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. IF FILE IS INITIAL. EXIT. ENDIF.
433
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. IF CONTAINER IS INITIAL. CREATE OBJECT CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS CNTL_ERROR OTHERS = 1 = 2.
CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT EXCEPTIONS CNTL_ERROR OTHERS = 1 = 3. CNTL_SYSTEM_ERROR = 2 = CONTAINER
IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. CLEAR V_URL. V_URL = FILE. CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. ENDIF.
434
*&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
Declaramos la tabla interna T_FILETAB de tipo FILETABLE, que no es ms que una tabla con un campo de 1024 caracteres de longitud.
435
*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, MY_PDF_VIEWER TYPE REF TO CL_GUI_PDFVIEWER, CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, W_SUBRC TYPE SY-SUBRC, V_URL TYPE CHAR255. * *=====================================================*
OK_CODE almacena el cdigo de funcin. MY_PDF_VIEWER es un objeto que nos permite visualizar un ALV. CONTAINER almacena el nombre de nuestro CUSTOM_CONTROL. W_SUBRC almacena el valor de retorno de llamar al mtodo FILE_OPEN_DIALOG. V_URL contiene la ruta donde se encuentra el ALV.
436
*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST.
Este parmetro, recoger la ruta donde se encuentra el PDF que queremos visualizar.
Llamamos a la pantalla 100 de nuestro Dynpro. El evento AT-SELECION-SCREEN se ejecuta cuando llamamos al parmetro FILE.
*&----------------------------------------------------* *& 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
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. IF FILE IS INITIAL. EXIT. ENDIF.
El mtodo FILE_OPEN_DIALOG nos muestra una ventana donde podemos elegir la ubicacin del archivo. Debemos leer la tabla interna T_FILETAB y asignar su contenido al parmetro FILE.
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. IF CONTAINER IS INITIAL. CREATE OBJECT CONTAINER EXPORTING CONTAINER_NAME = 'CUSTOM_ALV' EXCEPTIONS
438
CNTL_ERROR OTHERS
= 1 = 2.
CREATE OBJECT MY_PDF_VIEWER EXPORTING PARENT EXCEPTIONS CNTL_ERROR OTHERS = 1 = 3. CNTL_SYSTEM_ERROR = 2 = CONTAINER
IF NOT MY_PDF_VIEWER->HTML_VIEWER IS INITIAL. CLEAR V_URL. V_URL = FILE. CALL METHOD MY_PDF_VIEWER->OPEN_DOCUMENT EXPORTING URL = V_URL. ENDIF. ENDIF. ENDMODULE. " STATUS_0100 OUTPUT
Adems de asignar la barra de mens y el ttulo al programa, creamos el objeto CONTAINER que hace referencia a nuesteo CUSTOM_CONTROL, creamos el objeto MY_PDF_VIEWER que se mostrar dentro del objeto CONTAINER y llamamos al mtodo OPEN_DOCUMENT para abrir el archivo PDF que cargamos.
439
440
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE, T_FILETAB TYPE FILETABLE, RESULT_TAB TYPE MATCH_RESULT_TAB. *=====================================================* * DECLARACION DE VARIABLES DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP, SIZE TYPE I, INPUT_X TYPE XSTRING, OUTPUT_X TYPE XSTRING, W_SUBRC TYPE SY-SUBRC, W_FILE_IN TYPE STRING, W_FILE_OUT TYPE STRING, W_SIZE TYPE I, W_LINE TYPE STRING, W_EXT(4) TYPE C. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB, <FS_RESULT_TAB> LIKE LINE OF RESULT_TAB. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME, * *=====================================================* * *=====================================================* * *=====================================================*
441
FILE_OUT LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. DESCRIBE TABLE RESULT_TAB LINES W_SIZE. READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. W_SIZE = STRLEN( W_FILE_IN ) <FS_RESULT_TAB>-OFFSET. <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH. W_SIZE = W_SIZE - <FS_RESULT_TAB>-LENGTH. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE). CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB. = W_FILE_IN = 'BIN' * *=====================================================*
442
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER TABLES BINARY_TAB = DATA_TAB. = INPUT_X
IF CL_ZIP IS INITIAL. CREATE OBJECT CL_ZIP. ENDIF. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X. 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
CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME FILETYPE CHANGING DATA_TAB = DATA_TAB. = W_FILE_OUT = 'BIN'
*&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. = 'Seleccionar archivo' = '*.*' DEFAULT_FILENAME = '*.*'
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE_IN = <FS_FILETAB>. W_FILE_IN = FILE_IN. IF FILE_IN IS INITIAL. EXIT. ENDIF. CLEAR T_FILETAB.
444
REFRESH T_FILETAB. AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_OUT. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. = 'Seleccionar archivo' = '*.zip' DEFAULT_FILENAME = '*.zip'
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE_OUT = <FS_FILETAB>. W_FILE_OUT = FILE_OUT. IF FILE_OUT IS INITIAL. EXIT. ELSE. W_SIZE = STRLEN( W_FILE_OUT ). W_SIZE = W_SIZE - 4. W_EXT = W_FILE_OUT+W_SIZE(4). IF W_EXT NE '.zip'. CONCATENATE W_FILE_OUT '.zip' INTO W_FILE_OUT. FILE_OUT = W_FILE_OUT. ENDIF. ENDIF.
Revisemos un poco el cdigo. Nos es complicado, pero algunas cosas que pueden confundir un poco a simple vista.
445
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: DATA_TAB TYPE STANDARD TABLE OF T_XLINE, T_FILETAB TYPE FILETABLE, RESULT_TAB TYPE MATCH_RESULT_TAB. * *=====================================================*
Declaramos una tabla interna llamada DATA_TAB que hace referencia al TYPE T_XLINE, otra tabla llamada T_FILETAB que hace referencia a FILETABLE, que nos sirve para guardar las rutas de los archivos y finalmente RESULT_TAB de tipo MATCH_RESULT_TAB, que nos sirve para almacenar las ocurrencias de una bsqueda de texto.
*=====================================================* * DECLARACION DE VARIABLES DATA: CL_ZIP TYPE REF TO CL_ABAP_ZIP, SIZE TYPE I, INPUT_X TYPE XSTRING, OUTPUT_X TYPE XSTRING, * *=====================================================*
446
W_SUBRC TYPE SY-SUBRC, W_FILE_IN TYPE STRING, W_FILE_OUT TYPE STRING, W_SIZE TYPE I, W_LINE TYPE STRING, W_EXT(4) TYPE C.
CL_ZIP es un objeto que nos permitir comprimir el documento de entrada. SIZE determina el tamao del archivo que est siendo subido al servidor. INPUT_X guarda el contenido de convertir el archivo de Binario a Hexadecimal (Archivo de entrada). OUTPUT_X guarda el contenido de convertir el archivo de Hexadecimal a Binario (Archivo de salida). W_SUBRC almacena el resultado de ejecutar la accin de subir los archivos. W_FILE_IN almacena la ruta del archivo de entrada. W_FILE_OUT almacena la ruta del archivo de salida. W_SIZE almacena el tamao en lneas de la tabla interna RESULT_TAB. W_LINE almacena el nombre final que tendr el archivo de salida. W_EXT almacena la extensin del archivo de salida.
447
*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE_IN LIKE RLGRAP-FILENAME, FILE_OUT LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST.
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. FIND ALL OCCURRENCES OF '\' IN W_FILE_IN RESULTS RESULT_TAB. DESCRIBE TABLE RESULT_TAB LINES W_SIZE. READ TABLE RESULT_TAB INDEX W_SIZE ASSIGNING <FS_RESULT_TAB>. * *=====================================================*
448
W_SIZE = STRLEN( W_FILE_IN ) <FS_RESULT_TAB>-OFFSET. <FS_RESULT_TAB>-OFFSET = <FS_RESULT_TAB>-OFFSET + <FS_RESULT_TAB>-LENGTH. W_SIZE = W_SIZE - <FS_RESULT_TAB>-LENGTH. W_LINE = W_FILE_IN+<FS_RESULT_TAB>-OFFSET(W_SIZE). CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD EXPORTING FILENAME FILETYPE IMPORTING FILELENGTH = SIZE CHANGING DATA_TAB = DATA_TAB. = W_FILE_IN = 'BIN'
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING INPUT_LENGTH = SIZE IMPORTING BUFFER TABLES BINARY_TAB = DATA_TAB. = INPUT_X
IF CL_ZIP IS INITIAL. CREATE OBJECT CL_ZIP. ENDIF. CALL METHOD CL_ZIP->ADD EXPORTING NAME = W_LINE CONTENT = INPUT_X.
449
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
CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD EXPORTING BIN_FILESIZE = SIZE FILENAME FILETYPE CHANGING DATA_TAB = DATA_TAB. = W_FILE_OUT = 'BIN'
Buscamos todas las ocurrencias del smbolo \ dentro de la variable W_FILE_IN y guardamos el resultado en la tabla interna RESULT_TAB utilizando FIND ALL OCCURRENCES. Utilizamos un DESCRIBE TABLE para determinar la cantidad de registros generados y lo guardamos en W_SIZE. Leemos el ltimo registro de la tabla RESULT_TAB utilizando como ndice la cantidad de registros almacenados en la variable W_SIZE.
450
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 ubicacin del ltimo smbolo \ encontrado). Reemplazamos el valor del OFFSET, sumndole a este el valor del campo LENGTH (Es decir, la longitud del smbolo \). Restamos a W_SIZE el valor del campo LENGTH. Finalmente, 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 mtodo GUI_UPLOAD para subir el contenido del archivo de entrada. Con el mdulo de funciones SCMS_BINARY_TO_XSTRING convertimos el contenido del archivo de Binario a Hexadecimal. Creamos el objeto CL_ZIP y llamamos al mtodo ADD para agregar el archivo de entrada al nuevo ZIP, llamamos al mtodo SAVE para crear el archivo ZIP con el archivo de entrada. Con el mtodo SCMS_XSTRING_TO_BINARY convertimos el archivo ZIP de Hexadecimal a Binario y finalmente llamamos al mtodo GUI_DOWNLOAD para descargarlo con el nombre del archivo de salida.
*&----------------------------------------------------* *& 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
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE_IN = <FS_FILETAB>. W_FILE_IN = FILE_IN. IF FILE_IN IS INITIAL. EXIT. ENDIF. CLEAR T_FILETAB. REFRESH T_FILETAB.
Llamamos
al
mtodo
FILE_OPEN_DIALOG
para
poder
452
*=====================================================* * DECLARACION DE CONSTANTES CONSTANTS: LINE_LENGTH TYPE I VALUE 254. *=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. CALL SCREEN 0100. * *=====================================================* * *=====================================================* * *=====================================================*
453
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. PERFORM CALL_EDITOR. ENDMODULE. " STATUS_0100 OUTPUT
*&----------------------------------------------------* *& Module USER_COMMAND_0100 INPUT * *&----------------------------------------------------* MODULE USER_COMMAND_0100 INPUT. OK_CODE = SY-UCOMM. CLEAR SY-UCOMM. CASE OK_CODE. WHEN 'BACK' OR 'STOP' OR 'CANCEL'. SET SCREEN 0. LEAVE SCREEN. ENDCASE. ENDMODULE. " USER_COMMAND_0100 INPUT
454
*&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR . IF TEXT_EDITOR IS INITIAL. 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. 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
Declaramos una constante llamada LINE_LENGTH de tipo I con el valor 254. Esto determina cada cuantos caracteres debera hacer un salto de lnea automtico.
*=====================================================* * DECLARACION DE VARIABLES DATA: OK_CODE TYPE SY-UCOMM, CUSTOM_CONTAINER TYPE REF TO CL_GUI_CUSTOM_CONTAINER, TEXT_EDITOR TYPE REF TO CL_GUI_TEXTEDIT. * *=====================================================*
La variable OK_CODE almacena el cdigo de funcin. CUSTOM_CONTAINER es un objeto que crear el contenedor para nuestro control de texto. TEXT_EDITOR hace referencia al objeto que crea el control de texto.
456
*&----------------------------------------------------* *& Module STATUS_0100 OUTPUT * *&----------------------------------------------------* MODULE STATUS_0100 OUTPUT. SET PF-STATUS '100'. SET TITLEBAR '100'. PERFORM CALL_EDITOR. ENDMODULE. " STATUS_0100 OUTPUT
Asignamos el men y el ttulo del programa. Llamamos al FORM CALL_EDITOR. En donde llamamos al control de texto.
*&----------------------------------------------------* *& Form CALL_EDITOR * *&----------------------------------------------------* FORM CALL_EDITOR . IF TEXT_EDITOR IS INITIAL. CREATE OBJECT CUSTOM_CONTAINER
457
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. CALL METHOD CL_GUI_CFW=>FLUSH. ENDFORM. " CALL_EDITOR = 1 = 2 = 3 = 4 = 5 = 6. = CUSTOM_CONTAINER = = LINE_LENGTH CL_GUI_TEXTEDIT=>WORDWRAP_AT_FIXED_POSITION WORDWRAP_TO_LINEBREAK_MODE =
Creamos
el
contenedor
para
el
control
de
texto
Como podemos ver, contamos con dos botones Load Local File (Cargar archivo local) archivo local) y Save as Local File (Grabar como
459
WebDynpro
Introduccin
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 an muy difundido, es una herramienta muy potente y bastante sencilla de usar.
460
Elegimos de la lista Web Dynpro Comp. / Intf. (Componente o Interface Web Dynpro).
461
Creamos una vista, donde van a estar los componentes que muestran la informacin. Para esto, hacemos un clic derecho sobre ZDUMMY_DYPRO y seleccionamos Create View (Crear Vista).
462
En este momento, el servicio tiene que conectarse con el servidor, as que debemos ingresar nuestro usuario y password.
463
Node
464
Al nodo lo llamamos ZLENG_NODE y como Dictionary Structure (Estructura del Diccionario) le pasamos la vista ZVLENGUAJES_PROG.
Presionamos el botn Add Attribute from Structure (Agregar atributo desde estructura) Seleccionamos todos los campos. .
465
Como parmetro 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 pestaa Layout (Disposicin). Seleccionamos Standard Container (Contenedor Estndar) del men izquierdo y luego Group (Grupo).
467
Seleccionamos contenedor).
Create
Container
Form
(Crear
formulario
En la ventana que aparece a continuacin, debemos presionar el botn Context contenedor. para poder asignar un valor a nuestro
468
469
Si queremos probar como va quedando nuestro programa, debemos hacer lo siguiente. Seleccionamos ZDUMMY_DYNPRO con un doble clic.
470
471
Seleccionamos todos y aceptamos. Una vez que todo se ha activado, debemos crear una WebDynpro Application (Aplicacin WebDynpro).
472
El navegador nos muestra una pantalla de login, as que debemos logearnos. Para esto, presionamos el botn Log On .
473
Como podemos ver, nuestro parmetro de entrada aparece perfectamente en el browser de internet.
En este caso, el campo ID_PROG no tiene una ayda de bsqueda asociada, por lo cual por mucho que presionemos F4, no va a pasar nada. Cerremos el browser y retornemos a nuestro programa.
474
Regresamos a la vista ZDUMMY_VIEW, pestaa Layout. Elegimos el componente Table (Tabla) de la pestaa Standard Complex (Complejos Estndar).
Le asignamos un ttulo y hacemos clic derecho sobre el nodo TABLE para seleccionar Create Binding (Crear Atadura).
475
476
Regresamos a la pestaa Standard Simple y seleccionamos el control Button (Botn), el cual tendr el texto Mostrar!.
477
Debemos asignar una accin al botn, por lo cual presionamos el botn OnAction.
478
Debemos presionar el botn ABAP Routine (Rutina ABAP) para poder asignar el cdigo a nuestra accin.
METHOD ONACTIONSHOW. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE, ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. DATA: ID_PROG TYPE STRING. WD_CONTEXT->GET_ATTRIBUTE( exporting NAME = 'ID_PROG' importing VALUE = ID_PROG ). SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG EQ ID_PROG. NODE_LENG =
479
Declaramos la variable NODE_LENG que hace referencia a IF_WD_CONTEXT_NODE, esta es una interface que controla los nodos asociados a nuestro programa. ITAB_LENG es una tabla interna que hace referencia a la vista ZVLENGUAJES_PROG. ID_PROG es una variable de tipo String.
Obtenemos el valor de atributo ID_PROG, es decir, de nuestro parmetro de entrada. Seleccionamos el registro de la vista ZVLENGUAJES_PROG siempre y cuando cumpla con el parmetro 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.
480
Hay algo ms que debemos hacer y que es muy importante. Debemos ir a la pestaa Methods (Mtodos) y seleccionar WDDOINIT que es una accin que se lanza cuando se ejecuta el programa por primera vez.
method WDDOINIT. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE, ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. APPEND INITIAL LINE TO ITAB_LENG. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). NODE_LENG->BIND_TABLE( ITAB_LENG ). endmethod.
Lo ms resaltante de este cdigo, es que agregamos una lnea de cabecera a nuestra tabla interna, para que el Table Control tenga algo que mostrar cuando lanzemos el programa.
481
Todo se ve muy bien, pero estamos limitados a buscar solamente un valor...As que vamos a agregar otra caja de texto para poder crear un rango de bsqueda. 482
Renombramos el atributo ID_PROG a ID_PROG_INI, puesto que ahora vamos a tener dos atributos distintos. El nuevo atributo se llamar ID_PROG_FIN.
Ahora, creamos un nuevo nodo, llamado PARAMETROS que no contendr referencia a ningn tabla. Solamente nos servir como contenedor para los atributos.
483
484
Regresamos al Layout y eliminamos el campo de texto ID_PROG. Creamos un nuevo Container Form.
Nuestro diseo quedar como se muestra a continuacin, con dos parmetros de entrada, que nos servirn para definir nuestro rango.
485
METHOD ONACTIONSHOW. DATA: NODE_LENG TYPE REF TO IF_WD_CONTEXT_NODE, ITAB_LENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG. DATA: ID_PROG_INI TYPE STRING, ID_PROG_FIN TYPE STRING. DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'PARAMETROS' ).
486
WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). WD_CONTEXT->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ). APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. <FS_IDPROG>-SIGN = 'I'. <FS_IDPROG>-OPTION = 'BT'. <FS_IDPROG>-LOW = ID_PROG_INI. <FS_IDPROG>-HIGH = ID_PROG_FIN. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE ITAB_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG IN ID_PROG. NODE_LENG = WD_CONTEXT->GET_CHILD_NODE( NAME = 'ZLENG_NODE' ). NODE_LENG->BIND_TABLE( ITAB_LENG ). ENDMETHOD.
487
DATA: ID_PROG TYPE RANGE OF ZVLENGUAJES_PROG-ID_PROG. FIELD-SYMBOLS: <FS_IDPROG> LIKE LINE OF ID_PROG.
Declaramos dos variables, ID_PROG_INI e ID_PROG_FIN, cada cual almacenar el valor de su parmetro correspondiente. Declaramos la variable ID_PROG de tipo RANGE (Rango), con lo cual podremos definir un rango de valores para seleccionar de la vista. Declaramos un Field-Symbol.
Asignamos
el
nodo
PARAMETROS
nuestra
variable
NODE_LENG.
NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_INI' IMPORTING VALUE = ID_PROG_INI ). NODE_LENG->GET_ATTRIBUTE( EXPORTING NAME = 'ID_PROG_FIN' IMPORTING VALUE = ID_PROG_FIN ).
APPEND INITIAL LINE TO ID_PROG ASSIGNING <FS_IDPROG>. <FS_IDPROG>-SIGN = 'I'. <FS_IDPROG>-OPTION = 'BT'.
488
Agregamos una lnea de cabecera a nuestro rango, y asignamos los valores correspondientes. SIGN es el tipo de valor, OPTION es el tipo de correspondencia entre los datos, 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.
Between
En el select, reemplazamos el EQ por un IN, con lo cual podemos utilizar el rango para pasar ms de un valor como parmetro.
489
490
BSP
Introduccin
El BSP (Business Server Pages Pgina del Servidor de Aplicaciones), viene a ser un lenguaje script basado en ABAP, es decir, una especio de ASP, JSP o PHP. El BSP es anterior al WebDynpro, aunque esto no quiere decir que sea obsoleto o menos completo, por el contrario, lo que no se puede hacer con WebDynpro, se hace con BSP.
491
Creamos una pgina llamada index.bsp haciendo clic derecho Create Page (Crear Pgina).
492
Como podemos ver esta pgina, nos es ms que HTML con un par de caractersticas adicionales. onInputProcessing(show) nuestro FORM. navigation->set_parameter( ID_PROG ) nuestra pgina. Creamos una nueva pgina. Indica que estamos estableciendo el campo ID_PROG como un parmetro de salida de Evento llamado cuando se ejecuta una
493
494
<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. %> </table> </body> </html>
Como podemos ver, en esta pgina hemos incluido cdigo ABAP, dentro de los tags <% y %>. Adems hemos llamado variables utilizando los tags <%= y %>. Esto es porque el BSP es un lenguaje script y se integra perfectamente con el HTML. Simplemente recibimos un parmetro de la pgina index.bsp, seleccionamos datos y los mostramos en una tabla. Hasta ahora, estas dos pginas no se comunican entre s, as que vamos a agregar algo de cdigo para conectarlas. En la pgina index.bsp nos vamos a la pestaa Event Handler (Manejador de Eventos) y escogemos del men OnInputProcessing.
495
EVENT_ID es una variable que almacena los cdigos de funcin de las pginas. Si llamamos a nuestro FORM de la pgina index.bsp, establecemos el parmetro ID_PROG y llamamos a la pgina SHOW_DATA (Cabe destacar que este es un alias que definiremos en unos momentos). Nos vamos a la aplicacin con un doble clic.
496
Establecemos que index.bsp llama al alias SHOW_DATA que representa a la pgina Show_Data.bsp
Grabamos, activamos y ejecutamos, presionando el botn Test (Probar) servidor. o presionando F8.
497
498
Al ser HTML, podemos hacer lo que queramos con el formato de salida de la tabla, pero lo que vamos a hacer, al igual que con el WebDynpro, es crear un rango de valores para poder hacer una mejor seleccin en el programa. Regresamos a la pgina index.bsp y modificamos ligeramente el cdigo.
<%@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 parmetros ID_PROG_INI y ID_PROG_FIN. Vamos a la pestaa Event Handler y al evento OnInputProcessing.
499
Enviamos ambos parmetros a la pgina Show_Data.bsp En la pagna Show_Data.bsp hacemos un pequeos cambios.
<%@page language="abap" %> <html> <body> <% data: w_id_prog_ini type zvlenguajes_prog-id_prog, w_id_prog_fin type zvlenguajes_prog-id_prog, t_leng type standard table of ZVLENGUAJES_PROG, r_leng type range of ZVLENGUAJES_PROG-ID_PROG. field-symbols: <fs_leng> like line of t_leng, <fs_r_leng> like line of r_leng. append initial line to r_leng assigning <fs_r_leng>. w_id_prog_ini = request->get_form_field( 'ID_PROG_INI' ). w_id_prog_fin = request->get_form_field( 'ID_PROG_FIN' ). <fs_r_leng>-SIGN = 'I'. <fs_r_leng>-OPTION = 'BT'. <fs_r_leng>-LOW = W_ID_PROG_INI. <fs_r_leng>-HIGH = W_ID_PROG_FIN.
500
select ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_LENG FROM ZVLENGUAJES_PROG WHERE ID_PROG in r_leng. %> <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>. %> <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. %> </table> </body> </html>
Creamos un rango R_LENG, un field-Symbol <FS_R_LENG>, asignamos los parmetros de entrada W_ID_PROG_INI y W_ID_PROG_FIN al rango y lo utilizamos para nuestro select.
501
502
ABAP y XML
El XML (Extensible Markup Language Lenguaje extensible de marcas) es un formato de intercambio de archivos muy utilizado en al actualidad, puesto que es sumamente flexible. Como era de esperarse, el ABAP nos permite trabajar con archivos XML de una manera bastante simple.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB, LINE(100) TYPE C, END OF TY_TAB. *=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB, T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG, T_FILETAB TYPE FILETABLE. * *=====================================================* * *=====================================================*
503
*=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING, W_SUBRC TYPE SY-SUBRC, SIZE TYPE I, W_FILE TYPE STRING. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST. *=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM OBTENER_DATOS. PERFORM GENERAR_XML. PERFORM DESCARGAR_XML. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE = 'Seleccionar archivo' DEFAULT_FILENAME = '*.xml' * *=====================================================* * *=====================================================*
504
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. IF FILE IS INITIAL. EXIT. ELSE. W_FILE = FILE. ENDIF. *&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. ENDFORM. " OBTENER_DATOS
*&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. CALL TRANSFORMATION ('ID')
505
*&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. 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. " DESCARGAR_XML = W_FILE = 'BIN'
506
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB, LINE(100) TYPE C, END OF TY_TAB. * *=====================================================*
Declaramos un TYPE que contiene un solo campo llamado LINE de 100 de longitud y tipo C.
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB, T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG, T_FILETAB TYPE FILETABLE. * *=====================================================*
Creamos algunas tablas internas, una para guardar el XML, otra para guardar los datos de la Base de Datos y el ltimo para guardar la ruta del archivo de salida.
Declaramos un field-symbol.
507
*=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING, W_SUBRC TYPE SY-SUBRC, SIZE TYPE I, W_FILE TYPE STRING. * *=====================================================*
*&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST.
Declaramos un parmetro de entrada para poder obtener la ruta donde se generar el archivo XML.
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM OBTENER_DATOS. PERFORM GENERAR_XML. PERFORM DESCARGAR_XML. * *=====================================================*
508
OBTENER_DATOS nos sirve para seleccionar los datos de la vista. GENERAR_XML crea el archivo XML. DESCARGAR_XML guarda el archivo en la ruta especificada.
*&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. = 'Seleccionar archivo' = '*.xml' DEFAULT_FILENAME = '*.xml'
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. IF FILE IS INITIAL. EXIT. ELSE. W_FILE = FILE. ENDIF.
509
*&----------------------------------------------------* *& Form OBTENER_DATOS * *&----------------------------------------------------* FORM OBTENER_DATOS. SELECT ID_PROG NOM_PROG LENGUAJE ENTORNO INTO TABLE T_ZLENG FROM ZVLENGUAJES_PROG. ENDFORM. " OBTENER_DATOS
*&----------------------------------------------------* *& Form GENERAR_XML * *&----------------------------------------------------* FORM GENERAR_XML. CALL TRANSFORMATION ('ID') SOURCE TAB = T_ZLENG[] RESULT XML XML_OUT. ENDFORM. " GENERAR_XML
CALL TRANSFORMATION nos sirve para llamar a una transformacin que se encarga de convertir los datos de la tabla inerna en un cadena XML.
510
*&----------------------------------------------------* *& Form DESCARGAR_XML * *&----------------------------------------------------* FORM DESCARGAR_XML. 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. " 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. El mtodo GUI_DOWNLOAD nos permite descargar el archivo XML.
511
Ahora que ya vimos como podemos generar un archivo XML a partir de una tabla interna, veamos como hacer lo contrario, es decir, generemos una tabla interna en base a un archivo XML. El cdigo es practicamente el mismo, solo cambia el orden.
*=====================================================* * DECLARACION DE TYPES TYPES: BEGIN OF TY_TAB, LINE(100) TYPE C, END OF TY_TAB. * *=====================================================*
512
*=====================================================* * DECLARACION DE TABLAS INTERNAS DATA: T_TAB TYPE STANDARD TABLE OF TY_TAB, T_ZLENG TYPE STANDARD TABLE OF ZVLENGUAJES_PROG, T_FILETAB TYPE FILETABLE. *=====================================================* * DECLARACION DE FIELD-SYMBOLS FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB, <FS_ZLENG> LIKE LINE OF T_ZLENG. *=====================================================* * DECLARACION DE VARIABLES DATA: XML_OUT TYPE STRING, W_SUBRC TYPE SY-SUBRC, SIZE TYPE I, W_FILE TYPE STRING. *&----------------------------------------------------* *& SELECTION-SCREEN * *&----------------------------------------------------* SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME. PARAMETERS: FILE LIKE RLGRAP-FILENAME. SELECTION-SCREEN END OF BLOCK TEST. * *=====================================================* * *=====================================================* * *=====================================================*
513
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_XML. PERFORM GENERAR_TABLA_INTERNA. PERFORM IMPRIMIR. *&----------------------------------------------------* *& AT SELECTION-SCREEN * *&----------------------------------------------------* AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE. CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG EXPORTING WINDOW_TITLE FILE_FILTER CHANGING FILE_TABLE RC = T_FILETAB = W_SUBRC. = 'Seleccionar archivo' = '*.xml' DEFAULT_FILENAME = '*.xml' * *=====================================================*
READ TABLE T_FILETAB INDEX 1 ASSIGNING <FS_FILETAB>. FILE = <FS_FILETAB>. IF FILE IS INITIAL. EXIT. ELSE. W_FILE = FILE. ENDIF.
514
*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[]. ENDFORM. " GENERAR_TABLA_INTERNA
*&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. 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. ENDFORM. " CARGAR_XML = T_TAB
515
*&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. WRITE:/ <FS_ZLENG>-ID_PROG, <FS_ZLENG>-NOM_PROG, <FS_ZLENG>-LENGUAJE, <FS_ZLENG>-ENTORNO. ENDLOOP. ENDFORM. " IMPRIMIR
*=====================================================* * START-OF-SELECTION START-OF-SELECTION. PERFORM CARGAR_XML. PERFORM GENERAR_TABLA_INTERNA. PERFORM IMPRIMIR. * *=====================================================*
CARGAR_XML carga el archivo y lo guarda en un tabla interna. (Con formato XML claro est). Luego, lo transforma en una cadena XML. GENERAR_TABLA_INTERNA transforma la cadena XML en una tabla interna. IMPRIMIR muestra el resultado en pantalla.
516
*&----------------------------------------------------* *& Form CARGAR_XML * *&----------------------------------------------------* FORM CARGAR_XML. 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. ENDFORM. " CARGAR_XML = T_TAB
Utilizamos el mtodo GUI_UPLOAD para cargar el archivo XML. Con el mdulo de funciones SWA_STRING_FROM_TABLE convertimos la tabla interna en una cadena XML.
517
*&----------------------------------------------------* *& Form GENERAR_TABLA_INTERNA * *&----------------------------------------------------* FORM GENERAR_TABLA_INTERNA. CALL TRANSFORMATION ('ID') SOURCE XML XML_OUT RESULT TAB = T_ZLENG[]. ENDFORM. " GENERAR_TABLA_INTERNA
Utilizamos el CALL TRANSFORMATION para recibir una cadena XML y retornar una tabla interna.
*&----------------------------------------------------* *& Form IMPRIMIR * *&----------------------------------------------------* FORM IMPRIMIR. LOOP AT T_ZLENG ASSIGNING <FS_ZLENG>. WRITE:/ <FS_ZLENG>-ID_PROG, <FS_ZLENG>-NOM_PROG, <FS_ZLENG>-LENGUAJE, <FS_ZLENG>-ENTORNO. ENDLOOP. ENDFORM. " IMPRIMIR
Imprimimos el contenido de la tabla interna. Como pueden ver, es bastante sencillo trabajar con XML y ABAP.
518
519
Scripting in a Box
Scripting in a Box es una herramienta creada por Craig Cmehil de SAP AG. Esta herramienta basada en Eclipse, reune a todos los lenguajes script que pueden conectados con NetWeaver, como PHP, Ruby, Rails, Perl y Python. De muy sencilla instalacin, esta herramienta es indispensable para el trabajo con lenguajes script. La instalacin es lo mejor de todo, puesto que no existe una instalacin, al igual que el Eclipse, el Scripting in a Box simplementese descarga y se configura. Como era de suponerse, cuenta adems con varios ejemplos (Incluyendo mi emulador de SE16 en PHP), lo cual lo hace excelente para aquellas personas que nunca han hecho una integracin con NetWeaver. Para descargarlo, debemos ingresar a la siguiente direccin (Debemos ser usuarios del SDN SAP Developer Network). https://www.sdn.sap.com/irj/sdn/go/portal/prtroot/docs/library/uuid/e5 0bd86e-0a01-0010-53bd-857585234a6a O, ingresar a http://sdn.sap.com Tools for Developers Downloads More Downloadable
Scripting in a Box.
520
521
522
SAPLink
SAPLink es una herramienta creada por Daniel McWeeney y Ed Herrmann de Colgate - Palmolive. Esta herramienta, desarrollada en ABAP, nos permite crear una verdadera librera de cdigos para poder transportar o compartir con los dems. Creando paquetes basados en cdigo XML, podemos almacenar Programas, Dynpros, WebDynpros, SmartForms y un largo etctera. Si bien existen muchas herramientas para descargar y cargar elementos de NetWeaver (Yo he creado varias de ellas), no hay hasta el momento ninguna que pueda competir con SAPLink, puesto que SAPLink nos brinda una interfaz muy sencilla, opcin de descargar Plug-Ins y un constante monitoreo de los posibles errores. Podemos descargarla, debemos ingresar a la siguiente direccin. http://code.google.com/p/saplink/ Y para los Plug-Ins, deberemos ingresar a la direccin. http://code.google.com/p/saplink/wiki/pluginList Veamos algunas cuantas imgenes.
523
524
525
526
Integracin PHP-NetWeaver
Introduccin
El PHP (PHP Preprocessor), es un lenguaje de programacin para pginas web dinmicas. Lleva varios aos en el mercado, es open source y en su versin 5 en adelante, es un lenguaje orientado a objetos. Su sintaxis es bastante similar a la de C++, por lo cual, conociendo C++ o Java, es muy fcil de aprender. Gracias a Eduard Koucky, existe un conector llamado SAPRFC, que nos permite que las pginas web que desarrollemos en PHP, se conecten con NetWeaver, para obtener datos de tablas, ejecutar funciones, BAPIs, etc. Es decir, hacer lo mismo que hacemos todos los das, pero accediendo a travs de una interface web. Si se preguntan porque utilizar PHP con NetWeaver, en vez de utilizar WebDynpro o BSP, la respuesta es muy simple: PHP es gratuito, fcil de aprender y configurar. En todo caso, ya depende de cada uno que tecnologa utilizar. Lo nico que necesitamos para poder integrar PHP con NetWeaver es lo siguiente (Si no hemos instalado Scripting in a Box claro est): PHP versin 5.1.2 SAPRFC 1.4-5.0.4 MiniWas. 527 http://www.php.net http://httpd.apache.org http://saprfc.sourceforge.net/
Como este es un libro sobre NetWeaver y no sobre PHP (Para eso est, El Arte de Programar PHP), no vamos a ensear a instalar el PHP o el Apache, ni tampoco a programar en PHP, lo que vamos a hacer es configurar el SAPRFC e integrarlo con NetWeaver.
Instalando el SAPRFC
Simplemente debemos descomprimir el archivo .ZIP y copiar el archivo php_saprfc.dll, dentro de la carpeta /ext del PHP. En el PHP.ini debemos agregar la siguiente lnea.
extension = php_saprfc.dll;
Reiniciamos el servicio del Apache y estamos listos para comenzar. Para comprobar que todo est funcionando correctamente, simplemente llamamos a una pgina con el comando PHP_INFO().
528
<?php Class Login { var $Login, $rfc; function Login_Page() { PRINT("<DIV ALIGN='CENTER'><BR><BR><BR><BR><H1>PHP & SAP - SE16 Emulator</H1>"); PRINT("<BR><TABLE BORDER='1' BORDERCOLOR='BLUE' BGCOLOR='WHITE'>"); PRINT("<FORM ACTION='index.php' METHOD='POST'>"); PRINT("<TR><TD>Server</TD><TD><INPUT TYPE='TEXT' NAME='Server'></TD></TR>"); PRINT("<TR><TD>System Number</TD><TD><INPUT TYPE='TEXT' NAME='Sysnum' SIZE='3'></TD></TR>"); PRINT("<TR><TD>Client</TD><TD><INPUT TYPE='TEXT'
529
NAME='Client' SIZE='3'></TD></TR>"); PRINT("<TR><TD>User</TD><TD><INPUT TYPE='TEXT' NAME='User'></TD></TR>"); PRINT("<TR><TD>Password</TD><TD><INPUT TYPE='PASSWORD' NAME='Pass'></TD></TR>"); PRINT("<TR><TD COLSPAN='2' ALIGN='CENTER'><INPUT TYPE='SUBMIT' value='Log In' NAME='LOG_IN'>"); PRINT("<INPUT TYPE='RESET' value='Clear'></TD></TR>"); PRINT("</FORM>"); PRINT("<TABLE>"); PRINT("</DIV>"); } function Log_In($Server,$Sysnum,$Client,$User,$Pass) { $this->Login = array ("ASHOST"=>$Server, "SYSNR"=>$Sysnum, "CLIENT"=>$Client, "USER"=>$User, "PASSWD"=>$Pass, "CODEPAGE"=>"1404"); return $this->Login; } function RFC_Connection($Login) { $this->rfc = saprfc_open($Login); IF ( !$this->rfc ) { ECHO "The connection fails with the following
530
Lo que hacemos es crear algunas funciones. Login_Page Log_In ingresados. RFC_Connection Reestablecemos la conexin. Nos muestra la pantalla de logeo, donde debemos Nos conectamos a NetWeaver con los parmetros
Ahora, debemos crear la clase SE16.php que es la que va hacer todo el trabajo sucio.
531
function Show_Table($Table,$RFC_Me) { $this->fce = saprfc_function_discover($RFC_Me, "RFC_READ_TABLE"); IF (! $this->fce ) { ECHO "The function module had failed."; EXIT; } $Table = STRTOUPPER($Table); saprfc_import ($this->fce,"QUERY_TABLE",$Table); saprfc_import ($this->fce,"DELIMITER","/"); saprfc_table_init ($this->fce,"OPTIONS"); saprfc_table_init ($this->fce,"FIELDS"); saprfc_table_init ($this->fce,"DATA"); $rfc_rc = ""; $rfc_rc = saprfc_call_and_receive ($this->fce); if ($rfc_rc != SAPRFC_OK) { if ($rfc == SAPRFC_EXCEPTION ) echo ("Exception raised: ".saprfc_exception ($this->fce)); else echo ("Call error: ".saprfc_error ($this->fce)); exit; }
532
$data_row = saprfc_table_rows ($this->fce,"DATA"); $field_row = saprfc_table_rows ($this->fce,"FIELDS"); ECHO "<BR>"; ECHO "Table: " . $Table; ECHO "<BR><BR>"; ECHO "<TABLE BORDER='1' BORDERCOLOR='BLUE'>"; ECHO "<TR>"; for($i=1; $i<=$field_row ; $i++) { $FIELDS = saprfc_table_read ($this->fce,"FIELDS",$i); ECHO "<TD BGCOLOR='#4D80F6'>"; ECHO $FIELDS['FIELDNAME']; ECHO "</TD>"; } ECHO "</TR>"; for ($i=1; $i<=$data_row; $i++) { $DATA = saprfc_table_read ($this->fce,"DATA",$i); $TEST = SPLIT("/",$DATA['WA']); $rem = $i % 2; if($rem == 0) { ECHO "<TR BGCOLOR='#ADDEF7'>"; } else { ECHO "<TR BGCOLOR='#FFFFFF'>"; }
533
for($j=0; $j<$field_row; $j++) { ECHO "<TD>"; ECHO $TEST[$j]; ECHO "</TD>"; } ECHO "</TR>"; } ECHO "</TABLE>"; ECHO "<CENTER>"; PRINT("<FORM ACTION='index.php' METHOD='POST'>"); PRINT("<INPUT TYPE='HIDDEN' NAME='LOG_IN'><BR>"); PRINT("<INPUT TYPE='SUBMIT' value='Back' NAME='Back'>&nbs p; "); PRINT("</FORM>"); ECHO "</CENTER>"; } } ?>
Aqu tenemos una sola funcin, Show_Table, esta funcin recibe el nombre de la tabla que queremos visualizar, se conecta con el mdulo de funciones RFC_READ_TABLE, obtiene los datos y los muestra utilizando un formato de tabla de HTML. Vamos a analizar algunos puntos clave del cdigo.
$fce = saprfc_function_discover($rfc,RFC_READ_TABLE);
534
saprfc_table_init($fce,OPTIONS);
$rc = saprfc_call_and_recieve($fce);
$data_row = saprfc_table_rows($fce,DATA);
$DATA = saprfc_table_read($fce,DATA,$i);
echo($DATA[WA].\n);
saprfc_function_free($fce);
saprfc_close($fce);
Cerramos la conexin con SAP. Ahora, podemos continuar con las pginas PHP. La primera, es obviamente index.php
<?php session_start(); include("Login_Class.php"); ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF;text-align: center;} #login {background: #E5EAF6;border: 1px solid #C7D3EA;} </style> </head> <body> <?php if(isset($_POST['LOG_IN']) || (isset($_POST['Table'])))
536
{ if(!isset($_SESSION["Server"])) { $_SESSION["Server"] = $_POST["Server"]; $_SESSION["Sysnum"] = $_POST["Sysnum"]; $_SESSION["Client"] = $_POST["Client"]; $_SESSION["User"] = $_POST["User"]; $_SESSION["Pass"] = $_POST["Pass"]; } $Login = new Login(); $Log_Me = $Login->Log_In ($_SESSION["Server"],$_SESSION["Sysnum"], $_SESSION["Client"], $_SESSION["User"],$_SESSION["Pass"]); $RFC_Me = $Login->RFC_Connection($Log_Me); ECHO "<CENTER>"; PRINT("<FORM ACTION='Operation.php' METHOD='POST'>"); PRINT("<INPUT TYPE='TEXT' NAME='Table'><BR>"); PRINT("<INPUT TYPE='SUBMIT' value='Show Table' NAME='Show_Table'> "); PRINT("</FORM>"); ECHO "<A HREF='index.php'>Log Out</A>"; ECHO "</CENTER>"; } else { $_SESSION = array(); session_destroy();
537
En esta pgina, lo que hacemos es llamar a nuestra clase Login para poder conectarnos a NetWeaver y solicitar la tabla que queremos visualizar. La ltima pgina es Operation.php en donde llamamos a la clase SE16 para mostrar los datos en la tabla.
<?php session_start(); include("Login_Class.php"); include("SE16.php"); ?> <html> <head> <title>SE16 Simulation</title> <style> body {background: #F5F9FF;text-align: left;} #login {background: #E5EAF6;border: 1px solid #C7D3EA;} </style> </head> <body>
538
<?php $Login = new Login(); $Log_Me = $Login>Log_In($_SESSION["Server"],$_SESSION["Sysnum"], $_SESSION["Client"], $_SESSION["User"],$_SESSION["Pass"]); $RFC_Me = $Login->RFC_Connection($Log_Me); $SE16 = new SE16(); if(isset($_POST['Table'])) { $Table = $_POST['Table']; $SE16->Show_Table($Table,$RFC_Me); } ?> </body> </html>
539
540
Integracin Ruby-NetWeaver
Introduccin
Ruby es un lenguaje de programacin japons, creado hace ms de 11 aos por Yukihiro Matz Matsumoto. Ruby es un lenguaje de fcil aprendizaje, totalmente orientado a objetos y que hereda las caractersticas ms importantes de Perl y Python...Y como dice Matz, agrega todo lo que falta a esos dos lenguajes. Como no poda ser de otra forma, existe un conector para Ruby con NetWeaver, llamado SAP::Rfc creado por el genial Piers Harding. Lo nico que necesitamos para poder integrar Ruby con NetWeaver es lo siguiente. Ruby Versin 1.8.5 http://rubyforge.org/frs/download.php/12751/ruby18521.exe SAPRFC-0.19-mswin32.gem http://www.piersharding.com/download/ruby/saprfc-0.19mswin32.gem SAPRFC.so.win32 http://www.piersharding.com/download/ruby/saprfc.so.wi n32
541
Instalando el SAP::Rfc
Simplemente debemos hacer un GEM INSTALL SAPRFC-0.19mswin32.gem y listo. Para comprobar la instalacin basta con hacer un GEM LIST para obtener la lista.
542
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.new(:ashost => $Host.chop!, :sysnr :lang :user :trace => $Sysnr.chop!.to_i, => "EN", => $User.chop!, => 1)
# test the connection # print "is_connected: ", rfc.is_connected(), "\n" # lookup the interface for RFC_READ_TABLE itab = rfc.discover("RFC_READ_TABLE") print "\nEnter table: "
543
$Table = gets print "\n" itab.query_table.value = $Table.chop! itab.delimiter.value = "|" # do the RFC call rfc.call(itab) $Fields = Array.new $Data = Array.new $Data_Fields = Array.new $Data_Split = Array.new itab.fields.hashRows {|field| $Fields.push(field) } $Fields_Len = $Fields.length itab.data.hashRows {|field| $Data.push( field.to_s.strip!) } $Data_Len = $Data.length for i in 0...$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.split("|") for i in 1...$Fields_Len print $Data_Split[i].to_s.strip, "|" end print "\n\n" end print "\nclose connection: ", rfc.close(), "\n" print "Exit"
544
require rubygems gem saprfc require SAP/Rfc Llamamos a la librera de SAP::Rfc y especificamos que queremos utilizar el GEM.
rfc = SAP::Rfc.new(:ashost => $Host.chop!, :sysnr => $Sysnr.chop!.to_i, :lang => "EN", :client => $Client.chop!.to_i, :user => $User.chop!, :passwd => $Password.chop!, :trace => 1)
itab = rfc.discover("RFC_READ_TABLE")
545
rfc.call(itab)
itab.fields.hashRows {|field| $Fields.push(field) } $Fields_Len = $Fields.length itab.data.hashRows {|field| $Data.push(field.to_s.strip!) } $Data_Len = $Data.length
for i in 0...$Data_Len $Data_Fields = $Data[i] $Data_Split = $Data_Fields.split("|") for i in 1...$Fields_Len print $Data_Split[i].to_s.strip, "|" end print "\n\n" end
546
547
548
Bibliografa y agradecimientos
ABAP Objects : ABAP Programming in SAP NetWeaver de Horst Keller y Sascha Krger SAP Press. http://www.sappress.com/product.cfm?account=&product=H1934 Next Generation ABAP Development de Rich Heilman y Thomas Jung SAP Press. http://www.sappress.com/product.cfm?account=&product=H1986 El Arte de Programar SAP R/3 de Alvaro Tejada Galindo Lulu Press. http://www.lulu.com/content/561744 Hay muchas personas a quienes debo agredecer, puesto que me han apoyado mucho al momento de estar escribiendo este libro. Sin orden de importancia, mis agradecimientos... Mi esposa Milly y mi hija Tammy Luz, a quienes dedico este libro. A Thomas Jung y Rich Heilman (A quienes conoc en Las Vegas TechEd 2007 y gracias a ellos escrib este libro). A Craig Cmehil que siempre ha sido un Mentor para mi. A Cathy Welsh por facilitarme informacin valiosa sobre WebDynpro. A Abesh Bathacharjee quien con su amistad y sentido del humor me ayud a ser ms creativo.
549
Al SDN (SAP Developer Network) por haberme eligido como Mentor de SAP. A Mark Finnern por la confianza en mi que siempre ha demostrado. A Marilyn Pratt por haberme demostrado que Las abuelitas tambin pueden rockear.
550
Enlaces Web
Para terminar, quiero agregar algunos enlaces web que pienso que pueden ser bastante tiles. SDN (SAP Developer Network) BPX (Business Process Expert) El Blog Tecnolgico de Blag SAP ABAP en castellano SAP Press SAP Help SAP Marketplace http://sdn.sap.com http://bpx.sap.com http://atejada.blogspot.com
http://www.sap4.com
SAP
http://www.sap.com
551