jueves, 28 de julio de 2011

Grabar el resultado de una query en un fichero de texto

En esta entrada veremos como podemos descargar el resultado de una Query a un fichero de texto. En primer lugar deberemos añadir la ampliación SQUE0001 a un proyecto de ampliaciones mediante la transacción CMOD.

Esta user exit hace que en el formato de salida de la Query aparezca una nueva opción llamada "Archivo personal". Cuando marcamos este formato de salida se ejecuta el código de la user exit.

En la exit disponemos de los datos seleccionados por la Query de forma que podemos poner nuestro código para grabar esta tabla en un fichero (local o en el servidor de aplicaciones). Aquí os dejo el código para grabar la tabla en un fichero del servidor de aplicaciones utilizando la función Z_CREAERFICHERO publicada en una entrada anterior.

Los datos de la Query se encuentran en la tabla datatab.

CONSTANTS: c_zhr_contr_ns TYPE string VALUE 'ZHR_CONTR_NS',
c_zhr_contr_supl TYPE string VALUE 'ZHR_CONTR_SUPL',
c_interfaces TYPE string VALUE '/INTERFACES/GESTPRES/SALIDA',
c_extension TYPE string VALUE '.csv'.

IF sy-cprog CS c_zhr_contr_ns OR sy-cprog CS c_zhr_contr_supl.

DATA: ld_directory TYPE dxfile-filename,
ld_filename TYPE dxfile-filename.

* Construimos el nombre del fichero con el nombre de la query.
IF sy-cprog CS c_zhr_contr_ns.
CONCATENATE c_zhr_contr_ns '_' sy-datum c_extension INTO ld_filename.
ELSEIF sy-cprog CS c_zhr_contr_supl.
CONCATENATE c_zhr_contr_supl '_' sy-datum c_extension INTO ld_filename.
ENDIF.

ld_directory = c_interfaces.

* Generamos el fichero
CALL FUNCTION 'ZHR_CREARFICHERO'
EXPORTING
i_directory = ld_directory
i_filename = ld_filename
i_separator = ';'
i_overwrite = 'X'
it_data = datatab[]
EXCEPTIONS
ex_errordirectory = 1
ex_fileexists = 2
OTHERS = 3.

* Escribimos el log
IF sy-subrc NE 0.
* Mensaje de error
ENDIF.

Descargar cualquier tabla a un directorio del servidor de aplicaciones

Con esta función podremos descargar cualquier tabla, sea cual sea su estructura, a un fichero de texto en un directorio del servidor de aplicaciones. Podemos consultar los directorios mediante la transacción AL11.
Cómo parámetros le pasaremos el nombre del directorio, el nombre del fichero y la tabla de datos. Opcionalmente le podemos decir que sobreescriba el fichero en caso de que exista y el separador a utilizar entre los campos de una fila de datos.

FUNCTION z_crearfichero.
*"----------------------------------------------------------------------
*"*"Interfase local
*" IMPORTING
*" REFERENCE(I_DIRECTORY) TYPE DXFILE-FILENAME
*" REFERENCE(I_FILENAME) TYPE DXFILE-FILENAME
*" REFERENCE(I_OVERWRITE) TYPE CHAR1 OPTIONAL
*" REFERENCE(I_SEPARATOR) TYPE CHAR1 DEFAULT ';'
*" REFERENCE(IT_DATA) TYPE TABLE
*" EXCEPTIONS
*" EX_ERRORDIRECTORY
*" EX_FILEEXISTS
*"----------------------------------------------------------------------

* Verificamos la existencia del directorio de destino
DATA: lt_ocs_file LIKE ocs_file OCCURS 0,
ls_ocs_file LIKE ocs_file,
ld_directory LIKE ocs_file-name,
ld_filename LIKE ocs_file-name.

MOVE i_directory TO ld_directory.
MOVE i_filename TO ld_filename.

CALL FUNCTION 'OCS_GET_FILE_INFO'
EXPORTING
dir_name = ld_directory
file_name = '*'
TABLES
dir_list = lt_ocs_file
EXCEPTIONS
no_authority = 1
activity_unknown = 2
not_a_directory = 3
no_media_in_drive = 4
too_many_errors = 5
too_many_files = 6
bracket_error_in_filename = 7
no_such_parameter = 8.

* No podemos acceder al directorio o no existe
IF sy-subrc NE 0.
RAISE ex_errordirectory.
ENDIF.

* Comprobamos si existe.
READ TABLE lt_ocs_file INTO ls_ocs_file WITH KEY name = ld_filename.
IF sy-subrc EQ 0.
IF i_overwrite IS INITIAL.
* Si no podemos sobrescribirlo lanzamos una excepción
RAISE ex_fileexists.
ELSE.
* Si se puede sobreescribir damos una advertencia de ello
MESSAGE s007(zhrx_contratos_bold) WITH ld_filename.
* El fichero & se sobrescribe
ENDIF.
ENDIF.

* Bajamos la tabla al directorio de destino
DATA: ld_filepath TYPE dxfile-filename,
ld_length TYPE i,
ld_outdata TYPE string,
ld_data TYPE string.

FIELD-SYMBOLS: TYPE ANY.
FIELD-SYMBOLS: TYPE ANY.

* Construimos el nombre completo del fichero
CONCATENATE ld_directory ld_filename INTO ld_filepath SEPARATED BY '/'.

* Abrimos el fichero para escitura
OPEN DATASET ld_filepath FOR OUTPUT IN TEXT MODE ENCODING DEFAULT.
IF sy-subrc NE 0.
RAISE ex_errordirectory.
ENDIF.

* Para poder grabar cualquier tipo de tabla utilizamos field-symbols. En primer lugar leemos cada línea
* de la tabla asignandola al field symbols . En segundo lugar accedemos a cada uno de los campos
* de la fila mediante la instrucción ASSIGN COMPONENT. De esta forma podemos pasar a la función cualquier
* tipo de tabla independientemente de su estructura.
LOOP AT it_data ASSIGNING .
CLEAR: sy-subrc, ld_outdata.
* Leemos todos los campos de la estructura y los vamos concatenando para formar una línea del fichero
* de texto.
WHILE sy-subrc = 0.
ASSIGN COMPONENT sy-index OF STRUCTURE TO .
IF sy-subrc NE 0.
EXIT.
ENDIF.
CLEAR ld_data.
MOVE TO ld_data.
* El primer campo lo pasamos directamente a la variable de salida, el resto lo concatenamos mediante
* el separador especificado.
IF ld_outdata IS INITIAL.
MOVE ld_data TO ld_outdata.
ELSE.
CONCATENATE ld_outdata ld_data INTO ld_outdata SEPARATED BY i_separator.
ENDIF.
ENDWHILE.

* Añadimos al fichero destino la línea que acabamos de construir.
TRANSFER ld_outdata TO ld_filepath.
ENDLOOP.

* Cerramos el fichero de destino
CLOSE DATASET ld_filepath.

ENDFUNCTION.

jueves, 25 de noviembre de 2010

Deshabilitar un enhancement set en CRM Web UI

Dependiendo de la versión de CRM deberemos proceder de una forma u otra:
  • A partir de CRM 7.0 SP3 podemos mirar la nota 1311966.
  • Para versiones anteriores debemos poner un breakpoint en la BADI COMPONENT_LOADING. El breakpoint lo pondremos en el método GET_ACTIVE_ENHANCEMENT_SET de la implementación DEFAULT. Cuando se esté ejecutando la aplicación debemos limpiar la variable rv_result para que no coja dicho enhancement set. Es posible que posteriormente nos salga un mensaje diciendo que no existe el enhancement set cuando intentemos tratar el componente. En este caso deberemos restablecer en la vista BSPWDV_COMP_EXT el registro correspondiente a dicho componente.

jueves, 20 de noviembre de 2008

Como encontrar una BADI

Como encontrar la BADI que necesitamos

Existen varios métodos para encontrar la BADI que necesitamos pero nosotros vamos a explicar un método basado en la transacción ST05 (Performance Analysis).

Esta técnica de análisis se basa en el echo de que todas las BADIS’s están registradas en tablas de SAP. Por lo que en cada llamada a una Badi el sistema pasa por estas tablas. Las tablas de las BADIS son las siguientes SXS_INTER, SXC_EXIT, SXC_CLASS y SXC_ATTR. A estas tablas Sap siempre accede mediante las vistas V_EXT_IMP y V_EXT_ACT. Por lo que estas vistas (T: SE11) serán la base de nuestro análisis.

EJEMPLO:

Supongamos que quiero saber que BADIS son llamadas en la transacción “Maintain Business Partners” código BT

PASOS:

1.- Primero chequeamos que ningún otro usuario (T:SM04) o jobs en fondo (T: SM50) están usando el mismo usuario que tú.

2.- Nos vamos a la transacción ST05 (Performance Analysis) y marcamos el flag "Buffer trace", después pulsamos el botón “Activate Trace “, para activar el Trace.

3.- Inmediatamente después ya que el sistema está ya “Grabando” nos vamos a la transacción BT que queremos analizar y pulsamos el boton "Organization" completando los campos con los siguientes datos de prueba:


Al finalizar pulsamos el boton salvar.

4.- Volvemos a la ventana donde teníamos abierta la ST05 y pulsamos el botón "Deactivate Trace" para finalizar el trace y pulsamos sobre el botón "Display Trace", entonces el popup "Set Restrictions for Displaying Trace" aparecerá.

5.- Ahora vamos a filtrar el Trace con los objetos: V_EXT_IMP y V_EXT_ACT. Que son nuestras vistas.


Pulsamos el botón "Copy (FCool" , Fill Operations: OPEN y pulsamos el botón "Enter"

ANALISIS DE LOS RESULTADOS

Obtendremos un listado parecido a este que interpretaremos de la siguiente manera:




Todas las “interface class names” de las vista V_EXT_IMP comienzan con IF_EX_. Este es el prefijo estándar de Sap para las “ BAdI class interfaces “. El nombre de la BAdI está después de este IF_EX_.
Es decir el nombre de la BADi para IF_EX_ADDR_LANGU_TO_VERS es ADDR_LANGU_TO_VERS.

En la transacción SE18 puedes ver la definición de la BADI.


Aconsejamos durante la realización del Trace no ejecutar ninguna otra transacción o comando que no sean los propios de análisis si queremos obtener unos resultados lo más limpios posibles. Bien pues ya podéis realizar una función que propiamente es de analista .

No obstante podemos ver una lista de las BADI’s disponibles haciendo lo siguiente:
- Vamos a la Transacción SE18
- Pulsamos F4 para desplegar el matchcode
- Hacemos click en el icono “Sistema de información”
- Aumentamos el campo “Cant. Máxima aciertos” a 999999
Hacemos click en OK.

Se nos listará de esta forma las BADIS disponibles.

viernes, 27 de junio de 2008

Ventana vertical en SAPScript


En esta entrada explicaremos como crear una ventana vertical en un formulario SapScript. En la imagen aparece resaltada en rojo.
Lo que se debe hacer es lo siguiente:

1. Crear la ventana, con una anchura que solo permita escribir una letra por línea y con la variable con el texto que queremos imprimir.
2. En el programa de control (el que lanza el formulario), inicializaremos la variable anterior con el texto girado de forma que la primera letra sea la última. Por ejemplo, si queremos poner "Barcelona, 06 de mayo de 2008", en nuestra variable tendremos que tener el texto: "8002 ed oyam ed 60 ,anolecraB".
3. Con el software FontCreator (existe una versión de prueba de 30 días) creamos el tipo de letra que queremos utilizar. Para ello, yo he cogido el tipo de letra Arial, porque me interesaba esta tipografia, y la he renombrado a "Rotated". Luego rotamos todas las letras 90º. Este trabajo es un poco laborioso, y si queremos que quede bien tenemos que fijarnos donde alineamos las letras.
4. Instalamos la nueva fuente a SAP mediante la transacción SE73.
5. Creamos un tipo de fuente en el formulario con nuestra fuente, y lo aplicamos a la variable de la ventana vertical, y gualà, ya lo tenemos (mas o menos).
6. Modificamos el interlineado de la ventana vertical hasta que salga a nuestro gusto.

Un problema que encontré era que los espacios salian al lado de la letra precedente, y por lo tanto, el texto vertical estaba todo junto (sin espacios: Barcelona,06demayode2008), para solucionarlo debemos modificar una letra que jamás utilicemos de forma que sea un solo punto de 1x1 px, de forma que la impresora no lo imprima, pero que ocupe un espacio (yo lo he hecho con "_", de esta forma en lugar de escribir "Barcelona, 06 de mayo de 2008", escribimos "Barcelona,_06_de_mayo_de_2008". Debido al tamaño del punto, este no se imprime y el efecto resultante es como si hubieramos puesto un espacio).

Report con ALV

En esta entrada se explica como realizar un ALV. Primero necesitaremos una tabla con los campos que deseamos mostrar en el ALV. A esta tabla la hemos llamado gt_data. La tabla gt_data necesita que el primer campo se llame 'box' y sea de tipo boolean. A continuación esta el código necesario para crear el ALV. Una vez hayamos rellenado la tabla gt_data con los datos a mostrar, llamaremos a la función 'mostrar_alv' y listo. También será necesario crear un status llamado 'STATUS_ALV' con los botones típicos del ALV para ordenar, modificar el layout, hacer sumas, etc.




*&---------------------------------------------------------------------*
*& Include REPORT_TOP
*&---------------------------------------------------------------------*

TYPE-POOLS: slis.


CONSTANTS:
gc_formname_top_of_page TYPE slis_formname VALUE 'TOP_OF_PAGE',
evento_status TYPE slis_formname VALUE 'SET_STATUS',
evento_command TYPE slis_formname VALUE 'USER_COMMAND',
C_NO TYPE C VALUE '',
C_OK TYPE C VALUE 'X'.


DATA: gt_fieldcat TYPE slis_t_fieldcat_alv,
gs_layout TYPE slis_layout_alv,
gs_print TYPE slis_print_alv,
gt_sort TYPE slis_t_sortinfo_alv,
gt_sp_group TYPE slis_t_sp_group_alv,
gt_events TYPE slis_t_event,
g_repid LIKE sy-repid,
gt_list_top_of_page TYPE slis_t_listheader,
p_f2code LIKE sy-ucomm VALUE '&ETA',
g_boxname type c length 3 value 'BOX'.


* Definimos la tabla con los datos de salida, el primer campo debe ser 'box' de tipo 'boolean'
TYPES: BEGIN OF t_data,
box TYPE BOOLEAN,
. . .
end of t_data.




DATA: gt_data TYPE t_data OCCURS 0.





*&---------------------------------------------------------------------*
*& Include REPORT_ALV
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form construir_catalogo_eventos_alv
*&---------------------------------------------------------------------*
FORM construir_catalogo_eventos_alv
USING e03_lt_events TYPE slis_t_event.


DATA: ls_event TYPE slis_alv_event.


CALL FUNCTION 'REUSE_ALV_EVENTS_GET'
EXPORTING
i_list_type = 0
IMPORTING
et_events = e03_lt_events.


READ TABLE e03_lt_events WITH KEY name = slis_ev_top_of_page
INTO ls_event.
IF sy-subrc = 0.
MOVE gc_formname_top_of_page TO ls_event-form.
APPEND ls_event TO e03_lt_events.
ENDIF.


ENDFORM. " construir_catalogo_eventos_alv
*&---------------------------------------------------------------------*
*& Form construir_orden_alv
*&---------------------------------------------------------------------*
FORM construir_orden_alv USING e06_lt_sort TYPE slis_t_sortinfo_alv.


DATA: ls_sort TYPE slis_sortinfo_alv.


ls_sort-fieldname = 'PERNR'.
ls_sort-tabname = 'GT_DATA'.
ls_sort-spos = 1.
ls_sort-up = 'X'.
ls_sort-group = 'UL'.
* ls_sort-subtot = 'X'.
APPEND ls_sort TO e06_lt_sort.


ENDFORM. " construir_orden_alv
*&---------------------------------------------------------------------*
*& Form construir_cabecera_alv
*&---------------------------------------------------------------------*
FORM construir_cabecera_alv USING e04_lt_top_of_page TYPE slis_t_listheader.


DATA: ls_line TYPE slis_listheader,
texto(50) TYPE c,
separador(3) TYPE c.


CLEAR ls_line.
ls_line-typ = 'H'.
ls_line-info = text-001.
APPEND ls_line TO e04_lt_top_of_page.


CLEAR ls_line.
ls_line-typ = 'S'.
ls_line-info = text-002.
APPEND ls_line TO e04_lt_top_of_page.


ENDFORM. " construir_cabecera_alv
*&---------------------------------------------------------------------*
*& Form definir_layout_alv
*&---------------------------------------------------------------------*
FORM definir_layout_alv USING e05_ls_layout TYPE slis_layout_alv.


e05_ls_layout-f2code = p_f2code.
e05_ls_layout-zebra = c_ok.
e05_ls_layout-cell_merge = c_no.
e05_ls_layout-colwidth_optimize = c_ok.
e05_ls_layout-box_fieldname = g_boxname.
e05_ls_layout-no_input = c_no.
e05_ls_layout-no_vline = c_no.
e05_ls_layout-no_colhead = c_no.
CLEAR e05_ls_layout-lights_fieldname.


e05_ls_layout-totals_before_items = c_no.
e05_ls_layout-group_change_edit = c_no.
e05_ls_layout-lights_condense = c_no.
e05_ls_layout-totals_text = 'Totales '.
e05_ls_layout-subtotals_text = c_no.
e05_ls_layout-totals_only = c_no.
e05_ls_layout-key_hotspot = c_no.
e05_ls_layout-detail_popup = c_no.


ENDFORM. " definir_layout_alv
*---------------------------------------------------------------------*
* FORM top_of_page *
*---------------------------------------------------------------------*
FORM top_of_page.


CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE'
EXPORTING
i_logo = 'LOGO_COLOR'
it_list_commentary = gt_list_top_of_page.


ENDFORM. "top_of_page
*---------------------------------------------------------------------*
* FORM set_status *
*---------------------------------------------------------------------*
FORM set_status USING extab TYPE slis_t_extab.


* Si quisieramos excluir funciones del menu principal...
* DATA: fcode LIKE rsmpe-func.
* fcode = '&RNT_PREV'.
* APPEND fcode TO extab.


* SET PF-STATUS 'STATUS_ALV' EXCLUDING extab.




SET PF-STATUS 'STATUS_ALV'.


ENDFORM. "set_status
*---------------------------------------------------------------------*
* FORM user_command *
*---------------------------------------------------------------------*
FORM user_command USING r_ucomm LIKE sy-ucomm
rs_selfield TYPE slis_selfield.


CASE r_ucomm.
WHEN 'LOG'.
rs_selfield-refresh = 'X'.
CALL FUNCTION 'MESSAGES_SHOW'
EXPORTING
object = text-012
show_linno = space.
CLEAR r_ucomm.
ENDCASE.


ENDFORM. "user_command
*&---------------------------------------------------------------------*
*& Form construir_catalogo_campos_alv
*&---------------------------------------------------------------------*
FORM construir_catalogo_campos_alv USING e01_lt_fieldcat TYPE slis_t_fieldcat_alv.


DATA: ls_fieldcat TYPE slis_fieldcat_alv.


CONSTANTS: c_tabname LIKE ls_fieldcat-tabname VALUE 'GT_DATA'.


CLEAR ls_fieldcat.
ls_fieldcat-fieldname = 'NOMBRE_CAMPO'.
ls_fieldcat-tabname = c_tabname.
ls_fieldcat-seltext_l = text-0017.
APPEND ls_fieldcat TO e01_lt_fieldcat.


CLEAR ls_fieldcat.
ls_fieldcat-fieldname = 'NOMBRE_CAMPO'.
ls_fieldcat-tabname = c_tabname.
ls_fieldcat-seltext_l = text-003.
APPEND ls_fieldcat TO e01_lt_fieldcat.


. . .

ENDFORM. " construir_catalogo_campos_alv
*&---------------------------------------------------------------------*
*& Form mostrar_alv
*&---------------------------------------------------------------------*
FORM mostrar_alv.




PERFORM construir_catalogo_eventos_alv USING gt_events[].
PERFORM construir_catalogo_campos_alv USING gt_fieldcat[].
PERFORM construir_cabecera_alv USING gt_list_top_of_page[].
PERFORM definir_layout_alv USING gs_layout.
PERFORM construir_orden_alv USING gt_sort[].


CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
i_callback_program =sy-repid
i_callback_user_command = evento_command
i_callback_pf_status_set = evento_status
i_callback_top_of_page = gc_formname_top_of_page
is_layout = gs_layout
it_fieldcat = gt_fieldcat[]
it_special_groups = gt_sp_group[]
it_sort = gt_sort[]
i_save = 'A'
it_events = gt_events[]
TABLES
t_outtab = gt_data.


ENDFORM. " MOSTRAR_ALV