Skip to Content
Technical Articles
Author's profile photo Thiago Pereira

PDF Base 64 (string) para SAP FBL1N

Olá a todos Abapers Brasil,

Fiz algo simples no SAP, mas não encontrei tudo em um tópico somente. Então resolvi fazer esse post e irei tentar explicar do modo mais fácil possível.

O problema era: “tenho um arquivo PDF no portal e preciso anexa-lo na transação FBL1N”.

As ferramentas utilizadas foram SAP ECC 618 EHP 6, Abap Netweaver 7.51, SAP PO 7.5 SP01 e um portal qualquer com API Rest que retorne um JSON.

Fazendo algumas pesquisas descobri que a melhor forma de transitar um PDF é utilizando o PDF convertido em Base64 porém como string e não binário. Pois o binário não reconhece alguns caracteres especiais da nossa caligrafia.

A conversão de PDF para Base64 (STRING) pode ser feita facilmente via código (http://bit.ly/2Ft4vPE em JS) ou utilizando alguns sites que já fazem isso (http://bit.ly/2YgBCNP), o resultado é bem diferente do convencional, mais ou menos isso:

A comunicação para integrar com o PO foi feito no NodeJS e utilizei o Ngrok para fazer o proxy reverso. Simples, fácil e rápido e utilizei o Visual Studio Code para fazer o código.
Algo parecido com isso http://bit.ly/2Jw1ORj.

O PO é a parte mais simples de fazer.

No Enterprise Builder:

Nessa imagem já mostra boa parte do que foi feito. Todos os campos são strings pois estamos utilizando o Base64 string e não a binária.

Operation Mapping

No meu cenário eu não envio nada para fazer o get, porém o PO exige que passamos alguma informação, por isso estou passando um dummy.

No Integration Builder, foi somente a configuração do ICO para conectar com o Ngrok. Lembrado que toda a vez que o Ngrok é inicializado tem que ser alterada a URL do Communication Channel. Veja imagem abaixo.

Vamos agora ver a parte que interessa, a parte ABAP.

Na transação SPORXY criamos todos os objetos do PO que serão necessário para a leitura do NodeJS.

Depois no programa é criado a leitura do proxy que irá chegar até o NodeJS.

    DATA output TYPE update_pdf_dummy .
    DATA input TYPE return_update_pdf_sa.

    TRY.
        DATA(Base64_pdf) = NEW outbound_update_pdf( ).
        Base64_pdf->si_outbound_update_pdf_titulos(
          EXPORTING
            output             = output
          IMPORTING
            input              = input ).

      CATCH cx_ai_system_fault INTO DATA(system_fault).
        BREAK-POINT.
    ENDTRY.

O Resultado (input) virá o Base64 em string. A primeira coisa a fazer é executar a função SSFC_BASE64_DECODE.

DATA twebpdf TYPE string.
DATA fic_binario TYPE xstring.

    twebpdf = base64.

    CALL FUNCTION 'SSFC_BASE64_DECODE'
      EXPORTING
        b64data = twebpdf
      IMPORTING
        bindata = fic_binario.

Aqui iremos converter a string para xstring, que é a string que o SAP entende para fazer a conversão.

Logo após vamos criar uma tabela do tipo sdokcntbin e colocar o base64 dentro dela. Aproveitando o Try já coloquei o OPEN DATASET nele, pois irei gerar no servidor o arquivo. Se for gerar o arquivo local pode usar a GUI_DOWNLOAD para arquivos binários.

    DATA contents_tb TYPE TABLE OF sdokcntbin.
    DATA contents_st TYPE sdokcntbin.
    DATA file_length TYPE i.
    DATA flag        TYPE c.
    DATA off         TYPE i.
    DATA len         TYPE i.
    DATA file_name TYPE string VALUE '/usr/sap/tmp/'.

    TRY.
        len = xstrlen( fic_binario ).
        file_length = len.
        WHILE flag IS INITIAL.

          IF len LE 1022.
            contents_st-line = fic_binario+off(len).
            flag = 'X'.
          ELSE.
            contents_st-line = fic_binario+off(1022).
            off = off + 1022.
            len = len - 1022.
          ENDIF.
          APPEND contents_st TO contents_tb.
        ENDWHILE.

        CONCATENATE file_name filename INTO file_name.
        CONDENSE file_name NO-GAPS.

        OPEN DATASET file_name FOR OUTPUT IN BINARY MODE.
        LOOP AT contents_tb ASSIGNING FIELD-SYMBOL(<contents_fs>).
          TRANSFER <contents_fs> TO file_name.
        ENDLOOP.
        CLOSE DATASET file_name.

    ENDTRY.

Se você utilizou o GUI_DOWNLOAD irá ter o PDF já convertido, se utilizou o OPEN DATASET pode pegar o PDF utilizando a CG3Y ou na AL11. Lembre-se o formato é sempre BIN.

Não anexamos ainda na FBL1N, mas já temos o arquivo pronto.

Basicamente teremos que ler via OPEN DATASET, ou GUI_UPLOAD, o arquivo e armazenar em uma tabela tipo soli e converter todo o conteúdo para binário.

    DATA content_tb  TYPE  STANDARD TABLE OF soli.
    DATA content_st  TYPE soli.
    DATA file        TYPE string VALUE '/usr/sap/tmp/'.

    CONCATENATE file filename INTO file.
    OPEN DATASET file FOR INPUT IN BINARY MODE.
      WHILE sy-subrc = 0.
        READ DATASET file INTO content_st.

        APPEND  content_st TO content_tb.
      ENDWHILE.
    CLOSE DATASET file.

    CALL FUNCTION 'SO_CONVERT_CONTENTS_BIN'
      EXPORTING
        it_contents_bin = content_tb[]
      IMPORTING
        et_contents_bin = content_tb[].

Depois disso temos que pegar o ID da pasta que o SAP irá armazenar para mostrar na FBL1N, para isso usamos a função SO_FOLDER_ROOT_ID_GET. Utilizar como privado pois a compartilhada não é reconhecida pela transação.

    DATA folder_id   TYPE soodk.

      CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
        EXPORTING
          region                = 'B' “Privado
        IMPORTING
          folder_id             = folder_id
        EXCEPTIONS
          communication_failure = 1
          owner_not_exist       = 2
          system_failure        = 3
          x_error               = 4
          OTHERS                = 5.

O próximo passo é separar a extensão do arquivo do nome. Existem milhares de formas de fazer isso eu usei uma função, pode fazer como achar melhor. Com o split feito iremos armazenar na tabela objheader_tb concatenado ‘&SO_FILENAME=” e o nome do arquivo. Isso irá fazer com que a transação entenda o arquivo que irá ser aberto.

    DATA objhead_tb  TYPE STANDARD TABLE OF soli.
    DATA file_name   TYPE c LENGTH 100.
    DATA extension   TYPE c LENGTH 4.

      CALL FUNCTION 'CH_SPLIT_FILENAME'
        EXPORTING
          complete_filename = file
        IMPORTING
          extension         = extension
          name_with_ext     = file_name
        EXCEPTIONS
          invalid_drive     = 1
          invalid_path      = 2
          OTHERS            = 3.
      IF sy-subrc EQ 0.

        APPEND INITIAL LINE TO objhead_tb ASSIGNING FIELD-SYMBOL(<objhead_fs>).
        CONCATENATE '&SO_FILENAME=' file_name INTO <objhead_fs>.
      ENDIF.

A seguir iremos executar a função SO_OBJECT_INSERT, mas antes precisamos preencher as estruturas de pré-requisito dela. A objheader_tb foi preenchida acima e a content_tb mais acima.

    DATA content_tb  TYPE  STANDARD TABLE OF soli.
    DATA objhead_tb  TYPE STANDARD TABLE OF soli.
    DATA object_st   TYPE borident.
    DATA obj_id      TYPE soodk.
    DATA content_st  TYPE soli.
    DATA obj_data_st TYPE sood1.

      object_st-objkey  = objid.
      object_st-objtype = 'BSEG'.“BSEG pq é FBL1N outras transações isso muda
      obj_data_st-objsns = 'O'.
      obj_data_st-objla = sy-langu.
      obj_data_st-objdes = 'Attachment by Thiago'.
      obj_data_st-file_ext = extension.
      TRANSLATE obj_data_st-file_ext TO UPPER CASE.
      obj_data_st-objlen =  lines( content_tb ) * 255.

      CALL FUNCTION 'SO_OBJECT_INSERT'
        EXPORTING
          folder_id                  = folder_id
          object_type                = 'EXT'
          object_hd_change           = obj_data_st
        IMPORTING
          object_id                  = obj_id
        TABLES
          objhead                    = objhead_tb
          objcont                    = content_tb
        EXCEPTIONS
          active_user_not_exist      = 1
          communication_failure      = 2
          component_not_available    = 3
          dl_name_exist              = 4
          folder_not_exist           = 5
          folder_no_authorization    = 6
          object_type_not_exist      = 7
          operation_no_authorization = 8
          owner_not_exist            = 9
          parameter_error            = 10
          substitute_not_active      = 11
          substitute_not_defined     = 12
          system_failure             = 13
          x_error                    = 14
          OTHERS                     = 15.

E para finalizar só precisaremos executar a função BINARY_RELATION_CREATE_COMMIT, seguida de um COMMIT WORK.

    DATA folmem_k_st TYPE sofmk.
    DATA note_st     TYPE borident.
    DATA ep_note     TYPE borident-objkey.

        folmem_k_st-foltp = folder_id-objtp.
        folmem_k_st-folyr = folder_id-objyr.
        folmem_k_st-folno = folder_id-objno.
        folmem_k_st-doctp = folder_id-objtp.
        folmem_k_st-docyr = folder_id-objyr.
        folmem_k_st-docno = folder_id-objno.
        ep_note = folmem_k_st.
        note_st-objtype = 'MESSAGE'.
        note_st-objkey = ep_note.
        CALL FUNCTION 'BINARY_RELATION_CREATE_COMMIT'
          EXPORTING
            obj_rolea      = object_st
            obj_roleb      = note_st
            relationtype   = 'ATTA'
          EXCEPTIONS
            no_model       = 1
            internal_error = 2
            unknown        = 3
            OTHERS         = 4.
        IF sy-subrc EQ 0.
          COMMIT WORK.
        ENDIF.

Pronto, temos um PDF anexado na FBL1N.

 

Abraço a todos,

Thiago Pereira

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.