Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
thiago_pereira
Explorer
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