viernes, 30 de noviembre de 2007

Cubbic

Continúo en SAP hasta febrero, y a partir de ahí, continúo con un proyecto nuevo (para mí, porque el proyecto ya está empezado).
Se trata de un buscador en boletines oficiales españoles, de momento están indexados el BOME, el BOJA, y el BOCM (Melilla, Junta de Andalucía y Comunidad de Madrid).
Le pongo un link permanente y un banner.

http://www.cubbic.es (se me había olvidado)

jueves, 22 de noviembre de 2007

Comprobar la existencia de una RUTA

En primer lugar, hay que aclarar que en los sistemas UNIX, todo se trata como un fichero; por lo tanto, el siguiente report primero "chequea" si la ruta es UNIX o es WINDOWS, y después pasa a comprobarla.
*&---------------------------------------------------------------------*
*& Report Z_COMPROBAR_RUTA
*&
*&---------------------------------------------------------------------*
*& Comprueba si la RUTA de un fichero existe
*&---------------------------------------------------------------------*
*& Alberto García de Haro
*& http://misprogramasabap.blogspot.com
*&---------------------------------------------------------------------*
*& Elementos de datos:
*& p_unix: Fichero UNIX
*& p_locl: Fichero local (Windows)
*& p_ruta: Ruta del fichero
*&---------------------------------------------------------------------*

REPORT z_comprobar_ruta.

CONSTANTS: long TYPE i VALUE 1024.

DATA: gv_existe TYPE c,
gv_ruta TYPE string.

SELECTION-SCREEN BEGIN OF BLOCK bl1.
PARAMETERS:
p_unix RADIOBUTTON GROUP gr1,
p_locl RADIOBUTTON GROUP gr1,
p_ruta LIKE rlgrap-filename.
SELECTION-SCREEN END OF BLOCK bl1.

START-OF-SELECTION.
IF p_locl EQ 'X'. "Fichero local
MOVE p_ruta TO gv_ruta.

CALL METHOD cl_gui_frontend_services=>directory_exist
EXPORTING
directory = gv_ruta
RECEIVING
result = gv_existe
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
wrong_parameter = 3
not_supported_by_gui = 4
OTHERS = 5.
ELSE. "Fichero UNIX

OPEN DATASET p_ruta FOR INPUT
IN TEXT MODE ENCODING DEFAULT.
IF sy-subrc EQ 0.
gv_existe = 'X'.
CLOSE DATASET gv_ruta.
ELSE.
gv_existe = space.
ENDIF.

ENDIF.


PERFORM extraer_ruta USING p_ruta.

END-OF-SELECTION.
WRITE /.
IF gv_existe EQ space.
WRITE 'No existe la ruta'.
ELSE.
WRITE 'Sí existe la ruta'.
ENDIF.

*&---------------------------------------------------------------------*
*& Form extraer_ruta
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_GV_RUTA text
*----------------------------------------------------------------------*
FORM extraer_ruta USING p_gv_ruta.

*Tabla para ir metiendo las palabras
DATA:
BEGIN OF lt_tab OCCURS 10,
campo(long) TYPE c,
END OF lt_tab,

"Palabras
lv_word1(long) TYPE c,
lv_word2(long) TYPE c,


lv_ruta LIKE rlgrap-filename, "Ruta SIN fichero
lv_fich(long) TYPE c. "Nombre del fichero

*Inicio del proceso
REFRESH lt_tab.

MOVE p_gv_ruta TO lv_ruta.
DO.

SPLIT lv_ruta AT '/' INTO lv_word1 lv_word2.
IF NOT lv_word1 IS INITIAL and not lv_word2 is initial .
MOVE lv_word1 TO lt_tab.
APPEND lt_tab. CLEAR lt_tab.
ENDIF.
MOVE lv_word2 TO lv_ruta.

IF lv_word2 IS INITIAL. "No se puede separar más
MOVE lv_word1 TO lv_fich.
EXIT.
ENDIF.
ENDDO.
"Ahora obtengo la ruta

CLEAR lv_ruta.

LOOP AT lt_tab.
CONCATENATE lv_ruta lt_tab-campo
INTO lv_ruta SEPARATED BY '/'.
ENDLOOP.

WRITE:
'La ruta SIN fichero es',
lv_ruta, /,
'El fichero es',
lv_fich.

ENDFORM. " extraer_ruta

martes, 20 de noviembre de 2007

Leer checkboxes en un listado

Este problema se me planteó durante un borrado masivo de documentos preliminares.

Para ello, el propio SAP propone un report en su nota 971193. (Estaría bien poner los pdf en el blog, pero como son de SAP y tendrán copyright, mejor no).

El report que propone, básicamente, lista todos los documentos preliminares (parked documents), y al pulsar el botón de SAVE (para el que proponen un diskete, en el status DELE) se borran. Pero, ¿qué pasa si no quiero borrarlos todos?

Lo más fácil es poner, como encabezado de cada línea, un checkbox; y si está marcado se borra el documento correspondiente a esta línea. Para ello, hay que tener en cuenta lo siguiente:

1. El estatus DELE (al menos cuando empecé a trabajar con el report) tenía en el botón de “marcar todos” el código de función &ALL, que también estaba asociado a la tecla de función F2. Esto provocaba que, si se intentaba seleccionar sólo una línea, saltase el código de F2 que tenía asociada la función “Seleccionar todos (&ALL)”, y no funcionase. Para corregirlo, a la tecla de función “F2” le asocié el nuevo código “&ONE”, y para el código de función “&ALL” asocié la tecla de función F5, como puede apreciarse en las imágenes.
Además, agregué una función de refresco de imagen.




2. En el report propuesto, hice las siguientes modificaciones:
2.1. En la tabla TBKPF, añadí un campito para que recogiese/mostrase el valor del checkbox asociado:

data: begin of tbkpf occurs 5,
tratar type c.
include structure vbkpf.
data: end of tbkpf.

2.2. Tanto la selección de datos como la impresión por pantalla del listado, los metí en dos performs. Además, cambié la selección porque los bucles SELECT...ENDSELECT no me gustan. No tiene sentido mostrar el código de dichos performs (al final de esta entrada lo incluiré entero), sin embargo sus nombres son:

*Meto el select en un perform
perform seleccionar_vbkpf.

*Meto la impresión de la pantalla en otro perfrom
perform escribir_listado.

2.3. Al pulsar el botón de borrado (sy-ucomm = ‘DELE’), le pedí que revisara los documentos marcados con instrucciones READ LINE en la subrutina revisar_marcados; previamente, había guardado el número de líneas que se muestran por pantalla en la variable global gv_lineas declarada así:
data: gv_lineas like sy-linno.

Esta variable se establece después de hacer el listado con sentencias write (en concreto, en el perform “escribir_listado”, haciendo:
gv_lineas = sy-linno.
2.4. También al pulsar el botón de borrado, se llamaba al form “fbv0_dele.”. modifiqué una sóla línea de este form para que tuviera en cuenta que hiciera el loop a la tabla TBKPF, con la condición de que el campo “tratar” estuviera marcado, lo cual se revisaba como he dicho en el form revisar_marcados.

loop at tbkpf
"Añado condición
where tratar eq 'X'.
(...)
endloop.

3. Al escribir/leer el contenido de la tabla en el listado, hay que tener en cuenta que es preferible meter el checkbox en una variable global (gv_check) de tipo carácter, que escribir el campo de la tabla en sí (tbkpf-tratar), ya que en caso contrario cada vez que seleccionásemos una línea habría que modificar la tabla y reescribir el listado, con los inconvenientes que ello conlleva: modificar una tabla (aunque sea interna) es un proceso costoso, y un listado no se puede reescribir más de un número determinado de veces (según la parametrización del sistema donde hice el report, 20).
4. El botón “BACK” provocaba, durante el listado, que mostrase la pantalla anterior no por evento sino por apariencia; es decir, en lugar de mostrarse la pantalla de selección, aparecía la modificación anterior hecha en la pantalla. Por ejemplo, si después de ejecutar la pantalla de selección, durante el listado, primero seleccionábamos todos los check-boxes, luego los deseleccionábamos, luego marcábamos uno, y dábamos para atrás, resultaría que se mostrarían todos desmarcados (primera pulsación) luego todos marcados (segunda pulsación) y luego la pantalla de selección. ¡Un engorro! Por eso, deshabilité el botón “DELE” en el PF-STATUS:
start-of-selection.
set pf-status 'DELE' excluding 'BACK'.
Y lo volvía a incluirlo al pulsar el botón ‘DELE’.
end-of-selection.

at user-command.
(…)
case sy-ucomm.
when 'DELE'.
perform revisar_marcados. "Comprueba los marcados
set pf-status 'DELE'. "Habilita el botón “Back”


Estas han sido las modificaciones, ahora el report enterito:

*&---------------------------------------------------------------------*
*& Report ZDELEPARKED *&
*&---------------------------------------------------------------------*
*&
*& Borrado masivo de documentos preliminares
*& Modificado por Alberto García de Haro
*& a partir del report propuesto por SAP en la nota971193
*& 20 de noviembre de 2007
*& http://misprogramasabap.blogspot.com
*&---------------------------------------------------------------------*

report zdeleparked.

tables: vbkpf, t020.

data: mode type c value 'N'.
data: begin of tbkpf occurs 5,
tratar type c.
include structure vbkpf.
data: end of tbkpf.
data: begin of it020 occurs 0.
include structure t020.
data: end of it020.
data: begin of bdcdata occurs 0.
include structure bdcdata.
data: end of bdcdata.
data: begin of messtab occurs 0.
include structure bdcmsgcoll.
data: end of messtab.
data: char(20) type c,
count type i,
xdele.
data: wa_tbkpf like line of tbkpf,
gv_check type c,
gv_veces type i, "Veces que se ha mostrado el listado
gv_belnr like vbkpf-belnr,
gv_lineas like sy-linno,
gv_index like sy-tabix.

data: tmarcados like tbkpf occurs 10.
********pantalla de selección
select-options:
bukrs for vbkpf-bukrs memory id buk,
belnr for vbkpf-belnr,
gjahr for vbkpf-gjahr memory id gjr
default sy-datum(4).


selection-screen skip 1.
selection-screen begin of block 2 with frame title text-001.
select-options:
budat for vbkpf-budat,
bldat for vbkpf-bldat,
blart for vbkpf-blart,
xblnr for vbkpf-xblnr,
bktxt for vbkpf-bktxt,
usnam for vbkpf-usnam. "default sy-uname.
selection-screen end of block 2.

selection-screen begin of block 3 with frame title text-002.
select-options:
xwffr for vbkpf-xwffr,
xprfg for vbkpf-xprfg,
xfrge for vbkpf-xfrge.
selection-screen end of block 3.

**************eventos
initialization.
clear: gv_lineas, gv_veces.

at selection-screen.

start-of-selection.
set pf-status 'DELE' excluding 'BACK'.

call function 'AUTHORITY_CHECK_TCODE'
exporting
tcode = 'FBV0'
exceptions
ok = 1
others = 4.
if sy-subrc = 4.
message id sy-msgid type sy-msgty number sy-msgno
with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
exit.
endif.

*Meto el select en un perform
perform seleccionar_vbkpf.

*Meto la impresión de la pantalla en otro perfrom
perform escribir_listado.

end-of-selection.


at user-command.
clear gv_belnr.
clear: char.
if count > 0.

case sy-ucomm.
when 'DELE'.
perform revisar_marcados. "Comprueba los marcados
set pf-status 'DELE'. "Habilita el botón “Back”
if xdele = space.
call function 'POPUP_TO_CONFIRM_LOSS_OF_DATA'
exporting
titel = text-003
textline1 = text-004
textline2 = space
importing
answer = char(1).
if char(1) = 'J'.
perform fbv0_dele.
xdele = 'X'.
else.
exit.
endif.
else.
message i899(f5) with text-007.
endif.
when 'BACK'.

exit.

when '&ONE'. "Marca/desmarca uno.
perform marcar_uno.

when '&ALL'. "Marcar todos
perform marcar_todos.

when '&SAL'.
perform desmarcar_todos.
* when 'BACK'.

when 'FRSH'. "Refrescar
if gv_veces lt 20. "Sólo se permiten 20 anidamientos
perform seleccionar_vbkpf.
perform escribir_listado.
else.
message e368(00) with text-e01.
endif.
when others.
exit.
endcase.
endif.

*&---------------------------------------------------------------------*
*& Form FBV0_DELE
*&---------------------------------------------------------------------* *
*& Find out, how document was parked (classically or by ENJOY)
*&---------------------------------------------------------------------* *

form fbv0_dele.
refresh messtab.
loop at tbkpf
"Añado condición
where tratar eq 'X'.
clear t020.
select single * from t020 where tcode = tbkpf-tcode.
if t020-gener = space. "parked by classical transaction
perform fbv0_dele1 using tbkpf-gjahr
tbkpf-belnr
tbkpf-bukrs.
else. "parked by ENJOY
perform fbv0_dele2 using tbkpf-gjahr
tbkpf-belnr
tbkpf-bukrs.
endif.
endloop.
check sy-subrc eq 0.
loop at messtab.
write: / messtab.
endloop.
endform. "FBV0_DELE

*&---------------------------------------------------------------------*
*& Form FBV0_DELE1
*&---------------------------------------------------------------------*
*& Classically parked documents
*&---------------------------------------------------------------------*

form fbv0_dele1 using i_gjahr like bkpf-gjahr
i_belnr like bkpf-belnr
i_bukrs like bkpf-bukrs.

data: xdate(10) type c.
refresh bdcdata.
perform bdc_dynpro using 'SAPMF05V'
'0100'.
perform bdc_field using 'BDC_OKCODE'
'/00'.
perform bdc_field using 'BDC_CURSOR'
'RF05V-GJAHR'.
perform bdc_field using 'RF05V-BUKRS'
i_bukrs.
perform bdc_field using 'RF05V-BELNR'
i_belnr.
perform bdc_field using 'RF05V-GJAHR'
i_gjahr.
perform bdc_dynpro using 'SAPLF040'
'0700'.
perform bdc_field using 'BDC_CURSOR'
'BKPF-XBLNR'.
perform bdc_field using 'BDC_OKCODE'
'BL'.
perform bdc_dynpro using 'SAPLSPO1'
'0200'.
perform bdc_field using 'BDC_CURSOR'
'SPOP-OPTION1'. "Button YES
perform bdc_field using 'BDC_OKCODE'
'ENTER'.

call transaction 'FBV0' using bdcdata
mode mode
update 'S'.

call function 'MESSAGE_TEXT_BUILD'
exporting
msgid = sy-msgid
msgnr = sy-msgno
msgv1 = sy-msgv1
msgv2 = sy-msgv2
msgv3 = sy-msgv3
msgv4 = sy-msgv4
importing
message_text_output = messtab
exceptions
others = 4.
append messtab.
endform. "FBV0_DELE2

*&---------------------------------------------------------------------*
*& Form fbv0_dele2
*&---------------------------------------------------------------------*
*& Documents parked by ENJOY
*&---------------------------------------------------------------------*

form fbv0_dele2 using i_gjahr
i_belnr
i_bukrs.
data: xdate(10) type c.
refresh bdcdata.
perform bdc_dynpro using 'SAPMF05V'
'0100'.
perform bdc_field using 'BDC_OKCODE'
'/00'.
perform bdc_field using 'BDC_CURSOR'
'RF05V-GJAHR'.
perform bdc_field using 'RF05V-BUKRS'
i_bukrs.
perform bdc_field using 'RF05V-BELNR'
i_belnr.
perform bdc_field using 'RF05V-GJAHR'
i_gjahr.

if t020-koart = 'D'.
perform bdc_dynpro using 'SAPMF05A'
'1200'.
perform bdc_field using 'BDC_CURSOR'
'INVFO-ACCNT'.
elseif t020-koart = 'K'.
perform bdc_dynpro using 'SAPMF05A'
'1100'.
perform bdc_field using 'BDC_CURSOR'
'INVFO-ACCNT'.
elseif t020-koart = 'S'.
perform bdc_dynpro using 'SAPMF05A'
'1001'.
perform bdc_field using 'BDC_CURSOR'
'ACGL_HEAD-BLDAT'.
endif.

perform bdc_field using 'BDC_OKCODE'
'=9-PD'.

perform bdc_dynpro using 'SAPLSPO1'
'0200'.
perform bdc_field using 'BDC_CURSOR'
'SPOP-OPTION1'. "Button YES
perform bdc_field using 'BDC_OKCODE'
'ENTER'.

call transaction 'FBV0' using bdcdata
mode mode
update 'S'.

call function 'MESSAGE_TEXT_BUILD'
exporting
msgid = sy-msgid
msgnr = sy-msgno
msgv1 = sy-msgv1
msgv2 = sy-msgv2
msgv3 = sy-msgv3
msgv4 = sy-msgv4
importing
message_text_output = messtab
exceptions
others = 4.

append messtab.

endform. " fbv0_dele2

*&---------------------------------------------------------------------*
*& Form BDC_DYNPRO
*&---------------------------------------------------------------------*
form bdc_dynpro using program dynpro.
clear bdcdata.
bdcdata-program = program.
bdcdata-dynpro = dynpro.
bdcdata-dynbegin = 'X'.
append bdcdata.
endform. "BDC_DYNPRO

*&---------------------------------------------------------------------*
*& Form BDC_FIELD
*&---------------------------------------------------------------------*
form bdc_field using fnam fval.
clear bdcdata.
bdcdata-fnam = fnam.
bdcdata-fval = fval.
append bdcdata.
endform. "BDC_FIELD
*&---------------------------------------------------------------------*
*& Form seleccionar_vbkpf
*&---------------------------------------------------------------------*
* Selección de datos de la tabla vbkpf
*----------------------------------------------------------------------*

form seleccionar_vbkpf .
*Añado into corresponding fields
*Y cambio este select...endselect por un select
*into corresponding fields of table y hacer count = sy-dbcnt

* select * from vbkpf into corresponding fields of tbkpf
* where ausbk in bukrs
* and belnr in belnr
* and gjahr in gjahr
* and budat in budat
* and bldat in bldat
* and blart in blart
* and bktxt in bktxt
* and xblnr in xblnr
* and usnam in usnam
* and bstat eq 'V'
* and xwffr in xwffr
* and xfrge in xfrge
* and xprfg in xprfg.
* append tbkpf.
* count = count + 1.
* endselect.
* sort tbkpf by ausbk belnr gjahr.

"La tabla, bien limpita
clear tbkpf. refresh tbkpf.

select * from vbkpf
into corresponding fields of table tbkpf
where ausbk in bukrs
and belnr in belnr
and gjahr in gjahr
and budat in budat
and bldat in bldat
and blart in blart
and bktxt in bktxt
and xblnr in xblnr
and usnam in usnam
and bstat eq 'V'
and xwffr in xwffr
and xfrge in xfrge
and xprfg in xprfg
order by ausbk belnr gjahr.
clear count.
count = sy-dbcnt.

endform. " seleccionar_vbkpf
*&---------------------------------------------------------------------*
*& Form escribir_listado
*&---------------------------------------------------------------------*
* Muestra por pantalla el contenido de TBKPF, salvo el campo
* TBKPF-TRATAR; en su lugar escribe un CHECKBOX
*----------------------------------------------------------------------*

form escribir_listado .

if count = 0.
write: /, text-005.
else.
write: /, text-006, count, /.
uline.
*Una cabecera

write:
* at 3(5) 'AUSBK',
* at 9(5) 'BUKRS',
* at 15(10) 'BELNR',
* at 26(7) 'GJAHR'.
at 3(5) 'Soc.',
at 9(5) 'Soc.',
at 15(10) 'Doc.',
at 26(9) 'Ejercicio'.
uline.

format hotspot on.
loop at tbkpf.
gv_check = space.
write:
/,
gv_check as checkbox, "No escribe de tabla...
at 3(5) tbkpf-ausbk,
at 9(5) tbkpf-bukrs,
at 15(10) tbkpf-belnr,
at 26(7) tbkpf-gjahr.
hide: tbkpf-tratar, tbkpf-belnr.
endloop.
gv_lineas = sy-linno.
endif.
add 1 to gv_veces.


endform. " escribir_listado
*&---------------------------------------------------------------------*
*& Form revisar_marcados
*&---------------------------------------------------------------------*
* Al activar un checkbox, no se genera evento (no hay fcode)
* en este perform se revisan las casillas que están marcadas
* y se actualiza la tabla tbkpf usando la tabla local lt_tbkpf.
*----------------------------------------------------------------------*

form revisar_marcados.

data: wa_linea(255) type c,
lt_tbkpf like tbkpf occurs 5 with header line,
wa_tbkpf like line of tbkpf,
lv_belnr(10) type c,
lv_tratar type c,
lv_long type i,
lv_times type i.

clear:
wa_linea, lv_belnr, lv_tratar, lv_long, lv_times, lt_tbkpf.
refresh lt_tbkpf.

do gv_lineas times.

read line sy-index line value into wa_linea.
"Comprobamos que sea una línea con "datos"
"Y también que se tenga que tratar dicha línea
if wa_linea+2(4) eq 'AENA' and
wa_linea(1) eq 'X'.
"Comprobamos el CHECKBOX
lv_tratar = wa_linea(1).
"COMPROBAMOS EL PEDIDO
lv_belnr = wa_linea+14(10).
lv_long = strlen( lv_belnr ).
lv_times = 10 - lv_long.
do lv_times times.
concatenate '0' lv_belnr into lv_belnr.
enddo.
read table tbkpf with key belnr = lv_belnr.
"Modificamos la tabla si es necesario
if sy-subrc eq 0. "Ha leído la tabla
tbkpf-tratar = lv_tratar.
move-corresponding tbkpf to lt_tbkpf.
append lt_tbkpf. clear lt_tbkpf.
endif.
"La tabla se ha modificado
endif.
enddo.


* "Ahora modifico la tabla
loop at lt_tbkpf.
loop at tbkpf where belnr = lt_tbkpf-belnr.
tbkpf-tratar = 'X'.
modify tbkpf.
endloop.
endloop.

endform. " revisar_marcados
*&---------------------------------------------------------------------*
*& Form marcar_todos
*&---------------------------------------------------------------------*
* Marca todos los checkboxes del listado
*----------------------------------------------------------------------*

form marcar_todos .

do gv_lineas times.

read line sy-index field value gv_check.
gv_check = 'X'.
modify line sy-index field value gv_check.

enddo.

endform. " marcar_todos
*&---------------------------------------------------------------------*
*& Form DESMARCAR_TODOS
*&---------------------------------------------------------------------*
* Desmarca todos los checkboxes del listado
*----------------------------------------------------------------------*
form desmarcar_todos .

do gv_lineas times.

read line sy-index field value gv_check.
gv_check = ' '.
modify line sy-index field value gv_check.

enddo.


endform. " DESMARCAR_TODOS

*&---------------------------------------------------------------------*
*& Form marcar_uno
*&---------------------------------------------------------------------*
* Marca un solo elemento,
* - cuando se selecciona una línea (ya que FORMAT HOTSPOT = ON)
* - cuando se pulsa el botón &ONE (actualmente deshabilitado)
*----------------------------------------------------------------------*

form marcar_uno .

data: lv_lilli like sy-lilli.
lv_lilli = sy-lilli.

read line sy-lilli field value gv_check.
if gv_check eq 'X'.
gv_check = space.
else.
gv_check = 'X'.
endif.

modify line lv_lilli field value gv_check.

endform. " marcar_uno