Translate this blog

quarta-feira, 29 de maio de 2013

Pilha de Processos ABAP / ABAP Stack Process - LIFO


 Português  Quando debugamos um programa, podemos observar que existe uma tabela denominada Pilha ABAP na aba Standard. Nesta tabela contém as informações dos eventos, funções, métodos, etc. que o programa está realizando no momento. É a pilha de processos correntes no programa em execução, também conhecido como LIFO (Last In, First Out).

Existe a possibilidade de obter esta pilha por meio de código ABAP! Talvez seu uso não seja tão trivial, mas se algum dia precisarmos mapear os processos em execução, esta é a maneira!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
  DATA: lt_stack TYPE abap_callstack,
       ls_stack TYPE abap_callstack_line.
 
  CALL FUNCTION 'SYSTEM_CALLSTACK'
    IMPORTING
     callstack = lt_stack.
 
*Lendo os registros retornados da pilha
  LOOP AT lt_stack INTO ls_stack.
    WRITE: ls_abap-mainprogram,"Programa principal
     ls_abap-include,
     ls_abap-line,"Linha da chamada
     ls_abap-blocktype,"Tipo da chamada
     ls_abap-blockname,"Nome do processo
     "Processamento de sistema ou programa de sistema
     ls_abap-flag_system, /.
  ENDLOOP.

terça-feira, 28 de maio de 2013

Maneiras fáceis de montar o FieldCat / Easy ways to set the FieldCat


 Português  Os relatórios em ALV Grid são muito requisitados aos ABAPs. Existem algumas formas de fazê-lo, mas o que possibilita uma maior interação do ABAP para padronizá-lo é o Orientado a Objetos. Adicionar eventos, tratamentos com interação do usuário, etc. Normalmente, a maioria dos ABAPs já tem suas "receitas de bolos" para desenvolve-los mas... Porque não melhorá-los? Torná-los reutilizáveis talvez? Facilitar nossas vidas?
Para um primeiro post sobre ALV Grid, não vou me referir diretamente ao seu desenvolvimento. Demonstrarei algumas formas para montar o famoso Field Catalog (FieldCat), que é o responsável por montar a estrutura da tabela mostrada na tela do relatório. Ele que determina o comportamento do campo, se será editável ou não, seu comprimento, etc.
Dependendo da estrutura do seu relatório, você pode optar pela forma de montá-lo. Quando uso uma estrutura de uma tabela transparente ou mesmo de uma tabela com estrutura armazenada no SAP, eu utilizo a função LVC_FIELDCATALOG_MERGE. Sua utilização é bem simples:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
  DATA: lt_mara TYPE TABLE OF mara,
       lt_fldcat TYPE lvc_t_fcat.
  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
    EXPORTING
*    i_buffer_active =
     i_structure_name = 'MARA'
*    i_client_never_display = 'X' "Não mostra o mandante
*    i_bypassing_buffer =
     i_internal_tabname = 'LT_MARA'
    CHANGING
     ct_fieldcat = lt_fldcat
    EXCEPTIONS
     inconsistent_interface = 1
     program_error = 2
      OTHERS = 3.
*A informação de todos os campos existentes na MARA estarão
*contidas na tabela LT_FLDCAT e poderão ser passadas como
*parâmetro na hora de montar o ALV Grid.

No caso de um relatório mais personalizado, utilizando estruturas declaradas no programa que gera o relatório, desenvolvi um Form que busca as informações dos campos das tabelas DD02L, DD03L e DD03T com a ajuda da função DDIF_FIELDINFO_GET. Com esta função é possível extrair as informações Standards de cada campo da tabela interna declarada no report.
Vamos ao código:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
*Estrutura para armazenar a tabela e o campo Standard
  TYPES: BEGIN OF ty_tab_inf,
     tab TYPE dd02l-tabname,
     field TYPE dd03t-fieldname,
    END OF ty_tab_inf,
*Estrutura com os campos do relatório
    BEGIN OF ty_teste,
     matnr TYPE mara-matnr,
     belnr TYPE bseg-belnr,
    END OF ty_teste.
  DATA: lt_tab_inf TYPE TABLE OF ty_tab_inf,
   ls_tab_inf TYPE ty_tab_inf,
   lt_teste TYPE TABLE OF ty_teste,
   ls_teste TYPE ty_teste,
   lt_fldcat TYPE TABLE OF lvc_t_fcat.
*Adicionamos a tabela e campo de referência Standard,
*para montar o FieldCat conforme os campos do relatório
 ls_tab_inf-tab = 'MARA'. ls_tab_inf-field = 'MATNR'.
  APPEND ls_tab_inf TO lt_tab_inf.
 ls_tab_inf-tab = 'BSEG'. ls_tab_inf-field = 'BELNR'.
  APPEND ls_tab_inf TO lt_tab_inf.
  PERFORM zf_get_fieldcat USING 'LT_TESTE'
       lt_tab_inf
        CHANGING lt_fldcat.
*A informação de todos os campos existentes na LT_TESTE
*estarão contidas na tabela LT_FLDCAT e poderão ser passados
*como parâmetro na hora de montar o ALV Grid.
*&----------------------------------------------------------*
*& Form zf_get_fieldcat
*&----------------------------------------------------------*
* -->P_TABNAME text
* -->PT_TAB_INF text
* -->PT_FIELDCAT text
*&----------------------------------------------------------*
  FORM zf_get_fieldcat USING p_tabname TYPE lvc_tname
       pt_tab_inf TYPE ANY TABLE
        CHANGING pt_fieldcat TYPE lvc_t_fcat.
    FIELD-SYMBOLS: <fs_slin> TYPE ANY,
     <fs_tab> TYPE ANY,
     <fs_field> TYPE ANY.
    DATA: ls_fldcat TYPE lvc_s_fcat,
     lv_subrc TYPE sy-subrc.
   ls_fldcat-row_pos = 1.
    LOOP AT <fs_ttab> ASSIGNING <fs_slin>.
     ls_fldcat-col_pos = sy-tabix.
      ASSIGN( '<FS_SLIN>-TAB') TO <fs_tab>.
      ASSIGN( '<FS_SLIN>-FIELD') TO <fs_field>.
      IF <fs_tab> IS NOT ASSIGNED OR <fs_field> IS NOT ASSIGNED.
       lv_subrc = 4. EXIT.
      ENDIF.
      CALL FUNCTION 'DDIF_FIELDINFO_GET'
        EXPORTING
         tabname   = <fs_tab>
         fieldname = <fs_field>
         langu     = sy-langu
        TABLES
         dfies_tab = lt_dfies.
      IF sy-subrc IS INITIAL.
        READ TABLE lt_dfies INTO ls_dfies INDEX 1.
        MOVE-CORRESPONDING ls_dfies TO ls_fldcat.
       ls_fldcat-tabname = p_tabname.
        APPEND ls_fldcat TO pt_fieldcat.
      ENDIF.
    ENDLOOP.
   sy-subrc = lv_subrc.
  ENDFORM."zf_get_fieldcat

segunda-feira, 20 de maio de 2013

Estouro de variáveis decimais / Decimal variable's overflow


 Português  A conversão de dados em programação é sempre uma possivel causadora de problemas nos sistemas. Quando lidamos com sistemas que executam calculos que exigem minuciosidade com a integridade dos dados temos que ter o dobro de cuidado.

Os tipos de dados influenciam no comportamento das variáveis, podendo gerar um erro (Dump) que não tinha sido previsto anteriormente no desenvolvimento e nos testes. Por algumas vezes me deparei com essas situações, especialmente quando precisava calcular valores, alguns com casas decimais, outros não, estouro no tamanho da variável decimal, etc. Alguns nomes dos erros que me deparei até então são: COMPUTE_BCD_OVERFLOW, CONVT_OVERFLOW, CONVT_NO_NUMBER.

Analisando as soluções que identifiquei e algumas propostas de alguns colegas, acredito que a mais correta seria declarar a variável como tipo float (TYPE f), não correndo risco dos valores estourarem o tamanho da variável decimal ou mesmo o valor perder sua integridade. Mas como fazer pra mostrar o valor da variável float em uma mensagem, por exemplo?

Para executar esta conversão, desenvolvi uma função que formata o valor da variável Float para decimal e String, podendo ser definido o tipo de formatação e símbolo monetário desejádo (R$, $, etc):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  FUNCTION zfabap_format_float_type.
*"------------------------------------------------------------
*"*"Interface local:
*"  IMPORTING
*"     VALUE(I_FLOAT_VALUE) TYPE  FLOAT_VAL
*"     VALUE(I_WAERS) TYPE  WAERS DEFAULT 'USD'
*"     VALUE(I_SYMBOL) TYPE  CHAR3 OPTIONAL
*"  CHANGING
*"     VALUE(E_DECIMAL) TYPE  LONG_CURR OPTIONAL
*"     VALUE(E_CURRENCY) TYPE  STRING OPTIONAL
*"  EXCEPTIONS
*"      CONVERSION_OVERFLOW
*"------------------------------------------------------------
    DATA: lv_char TYPE c LENGTH 256.
 
    TRY.
        MOVE i_float_value TO e_decimal.
        WRITE e_decimal TO lv_char CURRENCY i_waers.
       e_currency = lv_char.
        IF i_symbol IS NOT INITIAL.
          CONCATENATE i_symbole_currency INTO e_currency.
        ENDIF.
        CONDENSE: e_currency NO-GAPS.
 
      CATCH cx_sy_conversion_overflow.
        RAISE conversion_overflow.
 
    ENDTRY.
  ENDFUNCTION.

No exemplo abaixo vou utilizar os elementos de dados WKURS (máximo de 9 posições com até 5 casas decimais) e BPREI (máximo 11 posições com até 2 casas decimais), onde a variável l_netpr estará preenchida completamente, não podendo ocorrer a adição de mais nenhuma casa decimal. No caso, estou forçando um possível estouro da variável, que não ocorrerá pelo fato de estar usando um tipo de variável float para receber o valor, fazendo utilização da função para conversão em decimal e String para a utilização do programador. A variável decimal receptora tem que ser do tipo LONG_CURR (30 posições, sendo duas posições decimais).

Vamos ao exemplo:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  DATA: l_wkurs TYPE wkurs VALUE '12.13000',
       l_netpr TYPE bprei VALUE '100000000.11',
       l_float TYPE float_val.
 
 l_float = l_netpr * l_wkurs.
 
*Caso a variável l_float fosse do tipo wkurs
*ou bprei ocorreria o estouro dela, acionando
*o erro SAP COMPUTE_BCD_OVERFLOW.
 
*Neste momento a var l_float é igual a 1.2130000013343000E+09
 
*No caso de mostrar o valor em
*uma frase para impressão ou exibição em
*tela, chamamos a função criada:
 
  DATA: l_val     TYPE long_curr,
       l_result  TYPE string.
 
  CALL FUNCTION zfabap_format_float_type
    EXPORTING
     i_float             = l_float
     i_waers             = 'BRL'
     i_symbol            = 'R$'
    CHANGING
     e_decimal           = l_val
     e_currency          = l_result
    EXCEPTIONS
     conversion_overflow = 1
      OTHERS              = 2.
*O resultado de l_val é 1213000001.33
*O resultado de l_result é R$1.213.000.001,33