Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
thiago_pereira
Explorer
Hello all Abapers,

I did something simple in SAP, but I did not find everything in one topic only. So I decided to do this post and I'll try to explain it as easily as possible.

The problem was: "I have a PDF file in the portal and I need to attach it to the FBL1N transaction."

The tools used were SAP ECC 618 EHP 6, Abap Netweaver 7.51, SAP PO 7.5 SP01 and any portal with API Rest that returns a JSON.



Doing some research I discovered that the best way to transpose a PDF is to use PDF converted to Base64, but as a string and not binary. For the binary does not recognize some special characters of our handwriting.

Conversion from PDF to Base64 (STRING) can be done easily via code (http://bit.ly/2Ft4vPE in JS) or by using some sites that already do this (http://bit.ly/2YgBCNP), the result is quite different from the conventional, more or less this:



The communication to integrate with the PO was done in NodeJS and I used Ngrok to make the reverse proxy. Simple, easy and fast. I used the Visual Studio Code to make the code.
Something like this http://bit.ly/2Jw1ORj.








198/5000
























PO is the simplest part to do.

In Enterprise Builder:

In this image already shows much of what was done. All fields are strings as we are using the Base64 string and not the binary.







Operation Mapping

In my scenario I do not send anything to do the "GET", but the PO requires that we pass some information, so I'm passing a dummy



In Integration Builder, it was just the configuration of ICO to connect with Ngrok. Remember that every time Ngrok is initialized, the URL of the Communication Channel must be changed. See image below.



Let's now see the part that matters, the ABAP part.

In the SPORXY transaction we create all the PO objects that will be needed for reading the NodeJS.



Then in the program is created the reading of the proxy that will get to the 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.

The Input will come from the Base64 string. The first thing to do is to execute the SSFC_BASE64_DECODE function.
DATA twebpdf TYPE string.
DATA fic_binario TYPE xstring.

twebpdf = base64.

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

Here we will convert the string to xstring, which is the string that SAP understands to do the conversion.

Soon after we will create a table of type sdokcntbin and put the base64 inside it. Taking advantage of the Try already put the OPEN DATASET in it, because I will generate in the server the file. If you are generating the local file you can use the GUI_DOWNLOAD for binary files.
    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.

If you used GUI_DOWNLOAD you will have the PDF already converted, if you used the OPEN DATASET you can get the PDF using CG3Y or AL11. Remember the format is always BIN.

We have not yet attached to FBL1N, but we already have the file ready.

Basically we will have to read via OPEN DATASET, or GUI_UPLOAD, the file and store in a table type soli and convert the entire contents to binary.
    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[].

After that we have to get the ID of the folder that SAP will store to show in FBL1N, for this we use the SO_FOLDER_ROOT_ID_GET function. Use as private because shared is not recognized by the transaction.
    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.

The next step is to separate the file extension from the name. There are thousands of ways to do this I've used a function, you can do as you see fit. With the done split we will store in the objheader_tb table concatenated '& SO_FILENAME = "and the name of the file. This will cause the transaction to understand the file that will be opened.
    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.

Next we will execute the SO_OBJECT_INSERT function, but before we need to fill in the prerequisite structures of it. Objheader_tb was populated up and content_tb higher up.
    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.

And to finish we just need to execute the BINARY_RELATION_CREATE COMMIT function, followed by a 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.

Okay, we have a PDF attached to FBL1N.



 

Tks,

thiago.pereira
5 Comments
Labels in this area