"
Apoiado por

Arquivo da categoria ‘Dicas’

Adeus DESCRIBE TABLE. Já vais tarde.

quatroemlinha

Durante doze anos
Quando quis contar
As linhas de uma itab
Fazia o que todos fazem:
DESCRIBE TABLE itab LINES linhas.

Até que outro dia
Vi uma coisa que,
Parece mentira,
Nunca antes vira:
LINES( itab ).

Dá no mesmo
E sem ter de declarar
O raio da variável.

Assim, em vez de:


DATA: linhas TYPE i.
DESCRIBE TABLE itabl LINES linhas.
IF linhas = 42.
  WRITE 'A tua tabela é a verdade'.
ENDIF.

Basta fazer:


IF LINES( itbl ) = 42.
  WRITE 'A tua tabela é a verdade'.
ENDIF.

É a prova de que
Se a SAP quisesse
Fazia um esforço
E o ABAP seria
Uma coisa fixe.

Mas parece que não quer
E o ABAP que se lixe.

Merda de poema. Foi o que se arranjou.

O Abapinho saúda-vos.

A mensagem travesti

Travesti

Nos módulos AT SELECTION-SCREEN de um REPORT é-te possível lançar mensagens de erro e voltar ao ecrã de selecção. Mas uma vez que passes do START-OF-SELECTION, se lançares uma mensagem de erro, o programa termina. A solução para dar um erro e, ainda assim, regressar ao ecrã de selecção, é travestir a mensagem:


START-OF-SELECTION.
  IF condicao_desejada.
    MESSAGE S001(00) with 'Erro!' DISPLAY LIKE 'E'.
    EXIT.
  ENDIF.
  WRITE 'Olá, eu sou o resto do programa'.

A mensagem do tipo S mascarou-se de E. Parece que É, mas não É.

Se experimentares vais ver que o sistema dá erro mas não sai completamente do programa; Volta ao ecrã de selecção e não corre o resto do programa (por causa do EXIT).

Obrigado Sérgio Lopes pela dica.

(E obrigado Tiago Celestino pela foto)

O Abapinho saúda-vos.

O circunlóquio do VALUE CHECK

rodeios

Nunca te aconteceu esbarrares com uma coisa no ABAP que parece que é mas não é? A documentação diz que é, tudo indica que assim seja, e depois afinal não é.

Provavelmente já precisaste de, ao definir um parâmetro no ecrã de selecção de um relatório, limitar as possibilidades do que o utilizador pode introduzir aos valores disponíveis no tipo de dados desse parâmetro, certo? Para isto existe o VALUE CHECK. Parece simples. Por exemplo, presumia-se que isto funcionasse:


PARAMETERS: P_BUKRS LIKE T001-BUKRS OBLIGATORY VALUE CHECK.

Vais a ver e não funciona.

O campo T001-BUKRS é do tipo BUKRS que é do domínio BUKRS que por sua vez tem definida a tabela de valores T001 para a qual BUKRS é a única chave primária. Mesmo assim, pateticamente, isto não funciona. Não funciona porque, por alguma razão lamentável, ao contrário do que faria sentido e se subentende na documentação, o VALUE CHECK não tem em conta o domínio do campo que valida. Pelo contrário, para este funcionar é preciso que o campo referido tenha uma chave externa para a tabela de valores.

Portanto, no nosso caso, embora a tabela que contém a lista de valores possíveis do BUKRS seja a T001, para o VALUE CHECK funcionar temos antes de fazer referência a uma outra tabela qualquer que tenha a T001 definida como chave externa. Como por exemplo, a T001K:


PARAMETERS: P_BUKRS LIKE T001K-BUKRS OBLIGATORY VALUE CHECK.

E assim já funciona.

Em resumo: conhecendo já tu a tabela com os valores possíveis, em vez de a poderes usar, tens de ir procurar outra que a defina como chave externa. É complicar o simples com rodeios. Um retórico chamar-lhe-ia circunlóquio. Eu chamo-lhe estupidez. Aposto que é um bug que a SAP decidiu orgulhosamente ignorar para sempre.

Obrigado Luís Rocha pela dica.

O Abapinho saúda-vos.

Variantes automáticas em reports

push

Quando se está a desenvolver um relatório com um ecrã de selecção, é muito chato de cada vez que o testamos ter de preencher o ecrã de selecção com os dados de teste. Normalmente acabamos por criar uma variante de teste para nos poupar a esse chatice. Mas mesmo assim, de cada vez que corremos o relatório, temos de invocar manualmente esta variante.

Aqui está uma forma simples de invocar automaticamente uma variante. Este código pode ser inserido no evento INITIALIZATION durante o desenvolvimento do programa:


INITIALIZATION.

  CALL FUNCTION 'RS_SUPPORT_SELECTIONS'
    EXPORTING
      report                     = sy-repid
      variant                    = 'TESTE'
 EXCEPTIONS
   VARIANT_NOT_EXISTENT       = 1
   VARIANT_OBSOLETE           = 2
   OTHERS                     = 3.

Obrigado Sérgio Fraga pela dica.

(E obrigado a Telstar Logistics pela foto)

O Abapinho saúda-vos.

De pé ó vítimas da fome

lili

Classes. Sempre as houve entre as pessoas. Mas no ABAP ainda há poucos que as tenham em conta. Se ser classicista na sociedade pode resultar em pedantismo, no ABAP, a única luta de classes é a que alguns travam para que estas sejam mais usadas.

Há dois tipos de classes: as globais e as locais. As globais são criadas na transacção SE24. As locais, que por sinal dou por mim a usar cada vez mais, são feitas declarativamente na SE38. Se soubermos que a nossa classe vai ser usada amiúde, faz sentido criá-la global. Se, pelo contrário, a classe for particular a um programa, não há porque fazer dela um objecto autónomo, bastando assim criá-la local ao programa que a vai usar.

Não é impossível que uma classe local se venha mais tarde a revelar útil noutro sítio. A hipótese mais estúpida, ainda que não inédita, é copiar o código de um programa para outro. Outra hipótese é colocá-la num “include” partilhado pelos vários programas que a usem. Mas mesmo isto também foleiro. Se é usada em mais que um sítio, ficará sempre mellhor como objecto global da SE24.

Os senhores da SAP, pensando já na possibilidade de uma classe local se emancipar, criaram uma ferramenta para isto. Funciona assim:

  1. Vai à SE24
  2. No menu “Tipo de objecto” escolhe a opção “Importar” e depois “classe local de programa”
  3. Escolhe o programa
  4. Aparece uma lista das classes locais desse programa
  5. scolhe as classes locais que queres tornar globais
  6. Dá-lhes um nome
  7. E pimbas

Se esta ferramenta não te parecer útil, vai comprar o livro ABAP para totós.

O Abapinho saúda-vos.

Esquece!

Cérebro

O SAP GUI tem boa memória. Vai decorando os valores que lhe vamos metendo nos campos e depois sugere-os quando, mais tarde, voltamos a esses campos. Mas às vezes decora coisas que mais valia esquecer. Como por exemplo quando introduzimos um valor errado e a seguir ele insiste em sugerir-nos esse valor errado.

Há uns tempos descobri que este pequeno drama tem solução. Quando, no campo, aparece a combo box com as várias hipóteses, usa as setas do teclado para te posicionares no valor que queres esquecer e depois carrega na tecla DELETE. E assim se faz o SAP GUI esquecer um valor.

(Obrigado a cloois pela foto)

O Abapinho saúda-vos.

SPLIT INTO TABLE

corta_fiambre

Aqui vos mostro uma forma criativa de preencher uma tabela interna com constantes que aprendi num programa standard. Imagina que querias criar uma tabela interna com os seguintes tipos de documento financeiro:

AB
AF
CH
DG
DZ
EX
F3
F4.

A forma mais convencional seria assim:


DATA: t_blart TYPE STANDARD TABLE OF blart,
      wa_blart LIKE LINE OF t_blart.

wa_blart = 'AB'.
APPEND wa_blart TO t_blart.
wa_blart = 'AF'.
APPEND wa_blart TO t_blart.
wa_blart = 'CH'.
APPEND wa_blart TO t_blart.
wa_blart = 'DG'.
APPEND wa_blart TO t_blart.
wa_blart = 'DZ'.
APPEND wa_blart TO t_blart.
wa_blart = 'EX'.
APPEND wa_blart TO t_blart.
wa_blart = 'F3'.
APPEND wa_blart TO t_blart.
wa_blart = 'F4'.
APPEND wa_blart TO t_blart.

Mas há uma forma muito mais sintética e curiosa:


DATA: lv_blart_list TYPE string,
      t_blart TYPE STANDARD TABLE OF blart,
      wa_blart LIKE LINE OF t_blart.

lv_blart_list = 'AB AF CH DG DZ EX F3 F4'.
SPLIT lv_blart_list AT space INTO TABLE t_blart.

O preenchimento da tabela é feito em apenas 2 linhas, bem menos que as 16 da forma convencional.

Fica aqui mais um exemplo copiado do standard que é interessante por ter dois níveis:


l_action_list = 'A01 A02 A03 A04'.
SPLIT l_action_list AT ' ' INTO TABLE lt_action.
LOOP AT lt_action INTO l_action.
  CASE l_action.
    WHEN 'A01'. l_refdoc_list = 'R01 R02 R03 R04 R05 R06 R14'.
    WHEN 'A02'. l_refdoc_list = 'R07 R08 R10 R12'.
    WHEN 'A03'. l_refdoc_list = 'R07 R08 R10 R11 R12 R13'.
    WHEN 'A04'. l_refdoc_list = 'R09'.
  ENDCASE.
  SPLIT l_refdoc_list AT ' ' INTO TABLE lt_refdoc.
  LOOP AT lt_refdoc INTO l_refdoc.
    ls_cust-action = l_action.
    ls_cust-refdoc = l_refdoc.
    APPEND ls_cust TO t_cust.
  ENDLOOP.
ENDLOOP.

O Abapinho saúda-vos.

Selecção vertical de texto no editor ABAP não dá? Dá!

ctrl-y

Como todos sabem, pode fazer-se selecções de blocos de texto verticais e horizontais em quase todo o lado do SAPGUI carregando em CTRL-Y e depois arrastando o rato para fazer a selecção. Como todos também sabem, isto não funciona no editor de ABAP. Mas o que provavelmente nem todos sabem é que há uma forma de fazer este tipo de selecções no editor de ABAP: primir e manter o ALT. Assim já podes seleccionar blocos de texto. Bom, não?

Obrigado Sérgio Fraga pela dica.

O Abapinho saúda-vos.

Parâmetros não parametrizáveis

baloico

Volta não volta aparece um cliente que pede a um funcional que pede a um programador que crie um parâmetro protegido contra escrita no ecrã de selecção de um programa. É um bocado cretino visto que a ideia dos parâmetros é serem parametrizáveis.

Mas enfim, vê-se de tudo.

Os clientes têm tanta imaginação que a SAP devia criar um módulo de cinema, SAP CI, especialmente para eles poderem realizar os tantos filmes que lhes vão na cabeça. Estou certo de que se criariam grandes sucessos de ficção científica. E muitas comédias também.

Bem, caso alguém te peça para fazer isto, faz-se assim:


REPORT ZTEST1.
PARAMETERS: nao_mexe LIKE mara-matnr DEFAULT '220705' MODIF ID ro.

AT SELECTION-SCREEN OUTPUT.
  LOOP AT SCREEN.
    IF SCREEN-GROUP1 = 'RO' .
      SCREEN-INPUT = '0'.
      MODIFY SCREEN.
    ENDIF.
  ENDLOOP.

START-OF-SELECTION.
  WRITE: / nao_mexe.

Agora falando mais a sério, a ideia de proteger parâmetros contra escrita é interessante se isso depender dos valores de outros parâmetros. Por exemplo, se o pisco “gravar ficheiro” estiver ligado, permite introduzir o nome do ficheiro, caso contrário, este último fica protegido contra escrita. Fica a sugestão. É só adicionar ao código as condições desejadas.

O Abapinho saúda-vos.

Saltando alegremente de ELSE em ELSE

cao_salta

Tens à tua frente um daqueles IF ELSEIF ELSEIF ELSEIF ELSEIF ELSE ENDIF gigantescos que atravessa centenas de linhas de código.

Se fizeres duplo clique em cima do IF ou de qualquer dos ELSEIF vais parar ao ENDIF. Se fizeres duplo-clique lá em baixo no ENDIF vais parar lá acima ao IF. Isto toda a gente sabe. Dá jeito com IF ENDIF pequeninos. Já com os grandes, não serve de muito.

Mas o que se calhar nem toda a gente sabe é que se fizeres ALT-clique no IF, em vez de ires parar directamente lá abaixo ao ENDIF, saltas só para o próximo ELSEIF e assim por adiante até chegares ao ENDIF.

Funciona tal e qual com o CASE WHEN WHEN WHEN WHEN WHEN ENDCASE.

Dá jeito.

(Obrigado Renato Sousa pela dica)
(E obrigado ao dj @ oxherder arts pela foto)

O Abapinho saúda-vos.

Saltos dentro do editor ABAP

salto_cavalo

Nunca te aconteceu estar a programar num programa ABAP daqueles que parecem um testamento com centenas e centenas de linhas e teres de estar sempre a saltar entre uma zona e outra do código?

Até há uns dias eu, ignorante, usava o PageUp e o PageDown para saltar entre os dois sítios e perdia montes de tempo à procura do lugar exacto do código que me interessava.

Mas entretanto o Sérgio Fraga ensinou-me que o editor ABAP tem uma funcionalidade chamada bookmarks que permite evitar o disparate de andar a subir e a descer às apalpadelas.

Primeiro é só fazer CTRL-ALT-1 numa determinada linha para nela definir o bookmark 1, CTRL-ALT-2 para definir o bookmark 2, e assim por adiante até ao 9.

Depois basta fazer CTRL-1 para saltar directamente para o bookmark 1, CTRL-2 para o 2 e assim por adiante.

Depois é só começar aos saltos de um lado para o outro como se não houvesse amanhã.

Já agora, os bookmarks também podem ser definidos através do menu que aparece quando se clica com o botão direito do rato na margem esquerda do editor.

Se saíres do editor estragas tudo porque os bookmarks não ficam gravados, mas mesmo assim, por serem tão simples de usar, dão muito jeito.

Obrigado Sérgio Fraga!

(E obrigado ao epi.us pela foto)

O Abapinho saúda-vos.

CASE de pernas para o ar

this_side_up

Qual é a tua cor preferida?


SELECTION-SCREEN BEGIN OF BLOCK b1.
PARAMETERS: p_azul BUTTONGROUP GROUP COR DEFAULT 'X',
            p_verde BUTTONGROUP GROUP COR,
            p_roxo BUTTONGROUP GROUP COR.
SELECTION-SCREEN END OF BLOCK b1.

Se respondeste azul sobrevives e podes atravessar a ponte.

De qualquer das formas, em ABAP costuma fazer-se o seguinte para descobrir a cor que o utilizador escolheu:


IF p_azul = 'X'.
  lv_cor = 'AZUL'.
ELSE IF p_verde = 'X'.
  lv_cor = 'VERDE'.
ELSE IF p_roxo = 'X'.
  lv_cor = 'ROXO'.
ENDIF.

Mas há uma forma curiosa e muito mais elegante de conseguir o mesmo. É aquilo a que se pode chamar de CASE de pernas para o ar:


CASE 'X'.
  WHEN p_azul.
    lv_cor = 'AZUL'.
  WHEN p_verde.
    lv_cor = 'VERDE'.
  WHEN p_roxo.
    lv_cor = 'ROXO'.
ENDCASE.

E esta, heim?

(Obrigado ao itspaulkelly pela foto.)

O Abapinho saúda-vos.

CTRL-clique para seleccionar uma palavra

rato

Uma dica simples mas valiosa: em qualquer sítio do SAP GUI – incluindo o editor de ABAP – para seleccionar uma palavra basta fazer CTRL-clique em cima dela. Fixe, não?

Infelizmente não funciona no GUI Java do Mac :-(

(Obrigado ao Sérgio Fraga pela dica)

O Abapinho saúda-vos.

RANGE instantâneo – É só juntar água

tang

Vou ensinar-te uma fórmula mágica para gerar um RANGE em que praticamente é só juntar água.

Imagina que queres fazer um RANGE a partir de uma seleção da base de dados para depois o utilizar num outro SELECT qualquer. Claro que o poderias fazer assim:


DATA: lt_kunnr TYPE STANDARD TABLE OF kunnr,
        lr_kunnr TYPE RANGE OF kunnr,
        wa_kunnr LIKE LINE OF lr_kunnr.
FIELD-SYMBOLS: <kunnr> LIKE LINE OF lt_kunnr.

SELECT kunnr
  INTO TABLE lt_kunnr
  FROM kna1.

wa_kunnr-sign = 'I'.
wa_kunnr-option = 'EQ'.
LOOP AT lt_kunnr ASSIGNING <kunnr>.
  wa_kunnr-low = <kunnr>.
  APPEND wa_kunnr TO lr_kunnr.
ENDLOOP.

E assim usaste 15 linhas de código e 4 variáveis.
Mas vê lá agora esta alternativa:


DATA: r_kunnr TYPE RANGE OF kunnr,
      wa_kunnr LIKE LINE OF r_kunnr.

SELECT kunnr AS low
  INTO CORRESPONDING FIELDS OF TABLE r_kunnr
  FROM kna1.

wa_kunnr-sign = 'I'.
wa_kunnr-option = 'EQ'.
MODIFY r_kunnr FROM wa_kunnr TRANSPORTING sign option WHERE low <> ''.

Repara como logo no SELECT renomeio logo o campo KUNNR para LOW por forma a poder metê-lo directamente no sítio certo do RANGE.
Repara também com o comando MODIFY actualiza de uma só vez todas as linhas do RANGE com apenas os campos que explicitamos.

E assim, usando apenas 10 linhas de código e 2 variáveis ficas com uma coisa que é mais sintética, mais bonita de se olhar e que manda muito mais sainete.

Granda pinta, não? É só vantagens.

Eu farto-me de usar isto.

Atenção que os RANGEs têm um limite de (não tenho a certeza mas acho serem) 2000 linhas.

O Abapinho saúda-vos.

Soneca

soneca

Volta não volta é preciso meter um programa a dormir. E como em quase tudo, há várias formas de o fazer, e umas formas são melhores do que outras.

A forma mais standard de conseguir isto em ABAP é a seguinte:


WAIT UP TO 10 SECONDS.

A vantagem do WAIT UP TO N SECONDS é que o processo é libertado durante estes 10 segundos, ficando assim disponível para quem o quiser apanhar. A grande desvantagem é que faz um COMMIT implícito, o que nem sempre é bom. Se não te importares com o COMMIT, esta é a melhor forma de adormeceres o teu programa. Nota que não dá para o adormecer por 1.5 segundos pois o parâmetro só aceita números inteiros.

Se um COMMIT não der jeito, porque tens um cursor aberto para a base de dados ou porque estás a meio de uma transacção, podes sempre fazer isto:


DATA: ZTIME LIKE SY-UZEIT.

GET TIME.

ZTIME = SY-UZEIT + 10.

DO.
  GET TIME.
  IF SY-UZEIT >= ZTIME.
     EXIT.
   ENDIF.
ENDDO.

Mas fazer isto é muito parvo. Chama-se espera activa e é a última coisa que queres fazer num programa porque é o mesmo que metê-lo a correr numa passadeira de ginásio: cansa-se e não chega a lado nenhum.

Felizmente há uma alternativa mais saudável que, embora não liberte o processo, evita o malfadado COMMIT:


CALL FUNCTION 'ENQUE_SLEEP'
    EXPORTING
        seconds    = 10.

O Abapinho saúda-vos.

Obrigado Sweet-Rainb0w pela foto.

Várias versões da mesma história

versoes-sap

Toda a gente sabe que as versões do SAP são uma grande confusão. Os senhores de Heidelberg que brincam a dar os nomes às coisas lá deles ou são uns caprichosos, ou andam a gozar connosco, ou devem andar sempre à bulha.

 
 

Aqui fica uma tabelinha para ajudar a deslindá-las:

 
Ano UI Edição Versão Versinha BASIS WebAS ECC NetWeaver
Terminal R/2 - -
1992 Desktop R/3 1.0 - 1.0
Desktop R/3 2.0, 2.1 - 2.0, 2.1
1997 Desktop R/3 3.0, 3.1 3.1I 3.1I
1998 Desktop R/3 4.0 4.0B 4.0B
2000 Desktop R/3 4.5 4.5B 4.5B
2001 Desktop R/3 4.6 4.6B, 4.6C 4.6B, 4.6C
2001 Desktop R/3 4.6D 4.6D 4.6D, 610 6.10
2003 Web R/3 Enterprise 1.10 4.7×110 620 6.20 NetWeaver (2003)
Web R/3 Enterprise 2.00 4.7×200 630 6.30 NetWeaver (2003)
2005 Web mySAP 2004 - 640 6.40 ECC 5.0 NetWeaver 04
2006 Web mySAP 2005 - 700 7.0 (AS) ECC 6.0 NetWeaver 04S

Se isto não for suficiente para deixares de estar confuso, aqui encontras uma apresentação muito boa e detalhada sobre as várias versões do SAP e as diferentes habilidades de cada uma.

O Abapinho saúda-vos.

(obrigado incurable_hippie pela foto)

Macros globais

makro

Noutro artigo falámos de macros, uma funcionalidade relativamente obscura e pouco utilizada que tanto pode ser útil como criar uma grande salganhada. Mas estas não são as únicas macros do ABAP. Há outras, ainda mais obscuras e com ainda maior potencial de enfarelhamento de um sistema: as macros globais.

Nem sei se revele isto de tão esquisito que é…
Mas também não me parece bem escondê-lo…
Seja, revelarei.

É possível definir macros a nível global do sistema que podem ser utilizadas em qualquer programa ABAP. Para isso existe a tabela TRMAC:

A utilização é evidente: NAME é o nome do macro, NUMM é o número da linha e LINE representa uma linha de código. Um macro com 3 linhas deverá ter 3 entradas na tabela TRMAC.

Agora que já sabes da existência destas macros, faz o favor de te esquecer delas. E se para ti o perigo da utilização destes macros não é evidente então tu também és um perigo. Porque é que me dou então ao trabalho de falar sobre esta aberração? Acima de tudo porque isto revela que o famoso comando “BREAK user” não é mais do que uma macro global, como podem ver pela imagem da tabela. Muito curioso.

(Obrigado ao Bruno Filipa pela dica)

O Abapinho saúda-vos.

Começar com o pé direito

pes-praia

Quando se faz login no SAP normalmente vai parar-se ao menu. Mas pode usar-se o módulo de função NAVIGATION_SET_START_TCODE para pré-definir uma transacção inicial. Vale o que vale, mas é melhor saber que existe do que não saber que existe e ainda melhor do que sabe que não existe. Quem sabe dê jeito a alguns utilizadores. Existe também o módulo de função NAVIGATION_GET_START_TCODE para ver qual está pré-definida.

O Abapinho saúda-vos.

Nem o Luís de Matos faria melhor

chaves

Às vezes acontece querermos aceder a uma transacção e não termos permissões. É uma chatice. Felizmente existe o módulo de função ALINK_CALL_TRANSACTION que alivia a situação. Mas usa com cuidado, não vá alguém zangar-se. Bem-vindo ao lado negro do Abapinho. Se disserem que fui eu que disse, nego tudo.

O Abapinho saúda-vos.

(obrigado ao Bohman pela foto)

Bate às portas certas

porta2

Para tua conveniência, aqui tens as portas TCP/IP utilizadas pelo NetWeaver Application Server ABAP e pelo Internet Connection Manager (ICM):

 


Serviço Número porta/Nome serviço Por defeito Fixo
Dispatcher 32NN/sapdpNN 3200 x
Gateway 33NN/sapgwNN 3300 x
Gateway 48NN/sapgwNNs 4800 x
ICM HTTP 80NN 8000  
ICM HTTPS 443NN Inactivo  
ICM SMTP 25 Inactivo  
Message Server 36NN/sapmsSID 3600/sapmsC11  
Message Server HTTP 81NN 8100  
Message Server HTTPS 444NN Inactivo  
Central System Log UDP: 12NN, 13NN, 14NN, 15NN Inactivo  

Para saberes mais consulta este documento da SAP.

O Abapinho saúda-vos.


Acerca do Abapinho
O Abapinho é suportado pelo WordPress
Artigos (RSS) e Comentários (RSS).