Librería ABAP
WordWind
Introducción
No dudo que, como en mi caso, la mera mención de la transacción SE71 o cualquier cosa relacionada con formularios o SmartForms provoca envejecimiento prematuro en el programador medio.
Hay que reconocer que la relación de SAP con las impresoras es mala. No sólo la dinámica de creación y edición de formularios es obsoleta, limitada y agobiante, sino que muchas veces el hecho nimio de cambiar de impresora hace que el formulario deje de comportarse como se esperaba, alterando sus márgenes, el zoom, etc…
Solución
Es por ello que he creado esta librería para acabar con los formularios de una vez por todas. No sólo es infinitamente más flexible que ellos, sino que el tiempo de programación se reduce más de 10 veces. Asimismo, los posibles cambios pueden ser llevados a cabo por el usuario simplemente modificando el template.
Empleo
La lógica es la siguiente: Se diseña un documento Word con gráficos, disposiciones, tipos de letra deseados, etc… y, en vez de valores fijos, se colocan las variables que deseemos sustituir. En el caso del ejemplo que adjunto:
Estimado/a Cliente:
Figura Usted en nuestros registros bajo el nombre _NAME1_, con residencia en _ORT01_ desde el _ERDAT_.
Asimismo figura usted de alta en las siguientes empresas del grupo:
_TABLA_
Lo grabaremos en formato .mht, que es HTML de mail, para que así quede almacenado como texto.
Después debemos diseñar un programa que tire de la librería que he creado, WordWind, abra este template y realice las sustituciones necesarias, especificando una carpeta de salida para los ficheros generados, en los que se han sustituido las palabras clave por los valores deseados.
Código de ejemplo
* REPORT zwordwindexample. "el motor que tira de esto INCLUDE zvcwordwind. "datos para el ejemplo TABLES kna1. DATA it_kna1 TYPE TABLE OF kna1 WITH HEADER LINE. DATA it_knb1 TYPE TABLE OF knb1 WITH HEADER LINE. " almacenamiento de los ficheros word DATA: stringtemplate TYPE string. DATA: stringword TYPE string. "cliente, sólo para el ejemplo SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME. SELECT-OPTIONS pkunnr FOR kna1-kunnr. SELECTION-SCREEN END OF BLOCK b01. "template y carpeta de descarga SELECTION-SCREEN BEGIN OF BLOCK b02 WITH FRAME. PARAMETERS: pfile LIKE rlgrap-filename LOWER CASE, pcarpeta(80) LOWER CASE. SELECTION-SCREEN END OF BLOCK b02. "selección de fichero AT SELECTION-SCREEN ON VALUE-REQUEST FOR pfile. PERFORM ww_getfilename CHANGING pfile. "selección de carpeta AT SELECTION-SCREEN ON VALUE-REQUEST FOR pcarpeta. PERFORM ww_getfolder CHANGING pcarpeta. START-OF-SELECTION. PERFORM carga_datos. PERFORM carga_template. PERFORM genera_salida. * carga datos de ejemplo de clientes FORM carga_datos. SELECT * FROM kna1 INTO TABLE it_kna1 WHERE kunnr IN pkunnr. SELECT * FROM knb1 INTO TABLE it_knb1 WHERE kunnr IN pkunnr. ENDFORM. "carga_datos * carga el template word FORM carga_template. ww_localfile2string pfile stringtemplate. ww_stripwordcrlf stringtemplate. ENDFORM. * genera la salida del word FORM genera_salida. DATA tabla TYPE string. LOOP AT it_kna1. "creamos una copia local del template como string stringword = stringtemplate. "hacemos las sustituciones directas ww_rep '_KUNNR_' it_kna1-kunnr stringword. ww_rep '_NAME1_' it_kna1-name1 stringword. ww_rep '_ORT01_' it_kna1-ort01 stringword. "fecha DATA lfecha1(10). WRITE it_kna1-erdat TO lfecha1. ww_rep '_ERDAT_' lfecha1 stringword. "generación de tabla, en HTML CLEAR tabla. "estilos CSS (habrá que añadir =3D en vez de = "dentro de los atributos del html: fijarse luego) concatenate '<style>' 'td{font-family:verdana;font-size:10pt;padding:2pt}' '.cabecelda{color:white;background-color:black;' 'border:1pt solid #000000;border-collapse:collapse}' '.fila{font-size:8pt;border:1pt solid #000000;border-collapse:collapse}' '.verdana{font-family:verdana;font-size:10pt}' '</style>' into tabla. "cabecera de tabla CONCATENATE tabla '<table width=3D"100%" cellspacing=3D0>' '<tr><td class=3Dcabecelda>SOCIEDAD</td>' & '<td class=3Dcabecelda>DESDE FECHA</td></tr>' INTO tabla. LOOP AT it_knb1 WHERE kunnr = it_kna1-kunnr. DATA lfecha2(10). WRITE it_knb1-erdat TO lfecha2. "filas de tabla CONCATENATE tabla '<tr><td class=3Dfila>' it_knb1-bukrs '</td><td class=3Dfila">' lfecha2 '</td></tr>' INTO tabla. ENDLOOP. "fin de tabla CONCATENATE tabla '</TABLE>' INTO tabla. "sustituimos en el template ww_rep '_TABLA_' tabla stringword. "limpiamos ww_ansi2html stringword. ww_setprintview stringword. "descargamos PERFORM download_fichero USING stringword it_kna1-kunnr. ENDLOOP. ENDFORM. * descargamos el fichero eligiendo un criterio " para su nombre, en este ejemplo el código de cliente FORM download_fichero USING pstring pkunnr. DATA lfilename LIKE rlgrap-filename. "añadimos \ a la carpeta ww_slashfolder pcarpeta. CONCATENATE pcarpeta 'CLIENTE_' pkunnr '.doc' INTO lfilename. "almacenamos en disco ww_string2localfile pstring lfilename. ENDFORM.
Observaciones
El código revela rápidamente que muchos de los procesos necesarios, como sustitución de caracteres, selección y apertura de ficheros, etc… están condensados en forma de macros. Esto ayuda a clarificar y compactar el código.
Nada más ejecutar el programa deberemos seleccionar el fichero template que utilizaremos como base para nuestra generación y la carpeta de salida donde se colocarán los ficheros procesados. A continuación, y esto es parte exclusiva del ejemplo, marcaremos un rango de clientes para sacar sus datos.
La sustitución de los datos simples es directa, con la macro ww_rep. Sin embargo, las tablas las deberemos programar como HTML+CSS. La primera vez cuesta: las siguientes serán mucho más sencillas.
Ampliación de funciones
Otras funciones de Word (en realidad, cualquier editor de textos que trabaje con formato .mht) se pueden deducir mediante ingeniería inversa. Por ejemplo, si queremos que una cabecera de tabla se repita de página en página deberemos meterla bajo el tag THEAD. Funciones como el paginado se las delegaremos exclusivamente al editor de texto como se hace en el caso de cualquier documento normal.
Seguridad y confidencialidad
El asunto de la seguridad es fácilmente gestionable. Podemos utilizar los programas generados con distintas variantes no editables según la función y el usuario que las deba ejecutar. Los ficheros template y las carpetas de salida pueden limitarse mediante permisos del SO para que sólo sean accesibles para los usuarios en cuestión.
La librería
La librería, este programa de ejemplo y se pueden descargar desde aquí.
Publico esta librería bajo licencia GPL sin limitaciones a la hora de alterar o ampliar el código, respetando siempre su autoría o autorías y conservando la licencia GPL. Su venta está prohibida.
A disfrutar.
Deja un comentario