In this article, we will see how to attach files to SAP business documents (objects) using Generic Object Services (GOS). First, we will understand the concept of GOS, then, how to use the GOS toolbox in GUI to attach files. Afterward, we’ll learn to implement an ABAP logic to attach a file interfaced through SAP Process Orchestration (SAP PI/PO) or SAP Cloud Platform Integration (CPI) from an external system. Finally, we will implement a custom ABAP program that can attach any type of file uploaded from your local PC to any SAP object.
If your requirement is to use ArchiveLink to store files, You can refer to the following articles,
Generic Object Services – GOS
Generic Object Services are a collection of common functionalities provided by SAP that business objects can reuse without having to implement ABAP codes. For example, GOS includes functionalities such as attaching a PDF to a document, entering a note, sending a document, starting a workflow, etc. The collection of these common functionalities provided by GOS is bundled together in the GOS toolbox for GUI mode use.
These common functionalities allow developers and SAP consultants to add them to any SAP business object with the minimum development effort.
In the screenshot above you can see the GOS toolbox and its function buttons displayed for SAP business object “credit memos”. What we will focus on in this article is the “create attachment” function of GOS.
How to Attach Files in GUI Using GOS
When the GOS is activated for an SAP business document type, you will be able to see the GOS toolbox from transactions related to that business object. For example, if GOS has been activated for sales orders, sales order change transaction VA02 and sales order display transaction VA03 will have the GOS toolbox.
Similarly, you can use the GOS toolbox for other business documents, such as Purchase Orders, Purchase Requisitions, Invoices, Accounting Documents, and even master data, such as Business Partner, Material Master, etc.
To attach a document, go to the desired transaction and click on the GOS toolbox, then click on “create” and then on “create attachment“. When a pop up appears, select the file location and click “ok”.
To view a list of files or notes attached to the object, use the option “Attachment List” on the toolbox.
Using GOS in Integration Scenarios
Let us assume a business scenario where Process Orchestration (SAP PI/PO) or Cloud Platform Integration (CPI) extracts files from an external sFTP location and routes them to SAP S4 HANA. In S4 HANA side, an ABAP program then attaches these files to corresponding business documents.
Following are a few examples of this type of integration scenario:
- Attaching invoice PDF to SAP sales order
- Attaching a picking list to SAP delivery note
- Linking digital signature to SAP invoice
SAP middleware fetches the files and encodes them in base64 format. On PI/PO side, you can use a User-Defined Function or a Java Mapping to encode file content to base64. Then the middleware routes the encoded message in base64 to SAP Application Integration Framework (AIF). The base64 format of the content should be decoded and attached to the SAP business document.
File Attachment ABAP Program Flow in AIF and S4 HANA
Now we will look at the data processing logic in SAP S4 HANA and AIF. That is, how to design and implement the ABAP code necessary to process the base64-encoded file and attach it to the SAP object.
Use the following FMs in the given sequence to convert the base64-encoded content and attach the file to the SAP object
- The first step of the processing is to decode the base64 format to XString format. XString is a predefined ABAP internal data type that represents the file content in a byte format. We can use the FM SCMS_BASE64_DECODE_STR for this purpose.
- The second step is to convert the XString format of the file to BIN format. FM SCMS_XSTRING_TO_BINARY allows us to convert XString format to BIN format.
- The third step is to convert the BIN format to SO uni-code format using FM SO_CONVERT_CONTENTS_BIN.
- The forth step of the logic is to create the address where your file is saved. For this we will use FM SO_FOLDER_ROOT_ID_GET.
- Next step is to insert the file content to the address (folder ID) created in the previous step. Use the FM SO_OBJECT_INSERT for this purpose.
- Finally, call the FM BINARY_RELATION_CREATE_COMMIT to link the file attached with the SAP business object/document.
Custom ABAP Program to Attach Files to SAP Documents
I was able to write a custom ABAP that showcases how to use some of the FMs I have described in the previous chapter. The purpose of the ABAP program is to attach any type of file uploaded from the local PC to an SAP business document, such as Sales Order, Delivery, Invoice, Account Document, etc.
You can specify the SAP document you would like to attach the file to using two selection parameters:
- Business Object Type – This corresponds to the SAP business object type. For example, BKPF for accounting documents, VBRK for invoices, VBAK for sales orders, LIKP for deliveries.
- Document number – The SAP business object document number.
SAP business object type and corresponding document number should match in order for the program to work as expected.
ABAP Code to Upload and Attach Files
Main Program
*&---------------------------------------------------------------------*
*& Report ZATTACH_FILE
*&---------------------------------------------------------------------*
*& Author: Isuru Fernando - SAPIntegrationHub.com
*&---------------------------------------------------------------------*
REPORT zattach_file.
DATA: gt_file_table TYPE filetable, "Uploaded file information
gt_content TYPE soli_tab, "Uploaded files content
gs_fol_id TYPE soodk, "Folder ID
gs_obj_id TYPE soodk. "Object ID
DATA: gv_ext TYPE sood1-file_ext, "File extension
gv_fname TYPE sood1-objdes. "File name
INCLUDE zattach_file_forms.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
PARAMETERS: p_path TYPE string OBLIGATORY. "File path
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
PARAMETERS: p_botype TYPE tojtb-name OBLIGATORY DEFAULT 'VBRK', "Business object type
p_doc_no TYPE vbeln OBLIGATORY. "Business document number
SELECTION-SCREEN END OF BLOCK b2.
INITIALIZATION.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.
PERFORM open_file_dialog USING p_path. "Open file upload dialog box
START-OF-SELECTION.
PERFORM upload_file USING p_path. "Upload file
PERFORM convert_to_bin. "Convert file content to BIN
PERFORM get_folder_root_id. "Get folder ID
PERFORM split_file_path USING p_path. "Find file extension and file name
PERFORM sap_office_object USING p_doc_no. "Create SAP office object
PERFORM create_binary_relation USING p_doc_no p_botype. "Link office object and doucment
Include
*&---------------------------------------------------------------------*
*& Include ZATTACH_FILE_FORMS
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form OPEN_FILE_DIALOG
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM open_file_dialog USING p_path.
DATA: ls_file_table LIKE LINE OF gt_file_table,
lv_rc TYPE i.
CLEAR p_path.
REFRESH: gt_file_table.
CALL METHOD cl_gui_frontend_services=>file_open_dialog
EXPORTING
window_title = 'Select File'
default_filename = '*.pdf'
multiselection = 'X'
CHANGING
file_table = gt_file_table
rc = lv_rc.
READ TABLE gt_file_table INDEX 1 INTO ls_file_table.
p_path = ls_file_table-filename.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form UPLOAD_FILE
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM upload_file USING p_path.
DATA: lv_len TYPE i.
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
filename = p_path
filetype = 'BIN'
IMPORTING
filelength = lv_len
TABLES
data_tab = gt_content.
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form CONVERT_TO_BIN
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM convert_to_bin .
CALL FUNCTION 'SO_CONVERT_CONTENTS_BIN'
EXPORTING
it_contents_bin = gt_content[]
IMPORTING
et_contents_bin = gt_content[].
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_FOLDER_ROOT_ID
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM get_folder_root_id .
CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
EXPORTING
region = 'B'
IMPORTING
folder_id = gs_fol_id
EXCEPTIONS
OTHERS = 1.
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form SAP_OFFICE_OBJECT
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM sap_office_object USING p_vbeln.
DATA:
ls_obj_data TYPE sood1,
lt_objhead TYPE STANDARD TABLE OF soli.
ls_obj_data-objsns = 'O'.
ls_obj_data-objla = sy-langu.
ls_obj_data-objdes = gv_fname.
ls_obj_data-file_ext = gv_ext.
ls_obj_data-objlen = lines( gt_content ) * 255.
CONDENSE ls_obj_data-objlen.
CALL FUNCTION 'SO_OBJECT_INSERT'
EXPORTING
folder_id = gs_fol_id
object_type = 'EXT'
object_hd_change = ls_obj_data
IMPORTING
object_id = gs_obj_id
TABLES
objhead = lt_objhead
objcont = gt_content
EXCEPTIONS
active_user_not_exist = 35
folder_not_exist = 6
object_type_not_exist = 17
owner_not_exist = 22
parameter_error = 23
OTHERS = 1000.
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form CREATE_BINARY_RELATION
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM create_binary_relation USING p_vbeln p_botype.
DATA:
ls_folmem_k TYPE sofmk,
ls_note TYPE borident,
lv_ep_note TYPE borident-objkey,
ls_object TYPE borident.
ls_object-objkey = p_vbeln.
ls_object-objtype = p_botype.
ls_note-objtype = 'MESSAGE'.
CONCATENATE gs_fol_id-objtp gs_fol_id-objyr gs_fol_id-objno gs_obj_id-objtp gs_obj_id-objyr gs_obj_id-objno INTO ls_note-objkey.
CALL FUNCTION 'BINARY_RELATION_CREATE_COMMIT'
EXPORTING
obj_rolea = ls_object
obj_roleb = ls_note
relationtype = 'ATTA'
EXCEPTIONS
OTHERS = 1.
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form SPLIT_FILE_PATH
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> P_PATH
*& --> P_EXT
*& --> P_FNAME
*&---------------------------------------------------------------------*
FORM split_file_path USING p_path.
DATA: lv_filename TYPE pcfile-path.
CHECK p_path IS NOT INITIAL.
lv_filename = p_path.
CALL FUNCTION 'PC_SPLIT_COMPLETE_FILENAME'
EXPORTING
complete_filename = lv_filename
* CHECK_DOS_FORMAT =
IMPORTING
* DRIVE =
extension = gv_ext
* NAME =
name_with_ext = gv_fname
* PATH =
EXCEPTIONS
invalid_drive = 1
invalid_extension = 2
invalid_name = 3
invalid_path = 4
OTHERS = 5.
PERFORM exception.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form EXCEPTION
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*& --> p1 text
*& <-- p2 text
*&---------------------------------------------------------------------*
FORM exception .
IF sy-subrc <> 0.
MESSAGE ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
To summarize, we talked about the concept of GOS and GOS functionality in GUI mode in the first chapters. Next, we discussed how to design an ABAP logic that can process and attach files transferred via an interface. Then we looked at the FMs needed to decode base64 format and attach files to a business document. Finally, we implemented an ABAP program that can upload files from local PC and attach them to SAP business documents.
If you have any questions or comments, please post them below.
ABAP program logic to attach an interfaced file to an SAP document
I have followed all the 6 steps to receive the XML payload from SuccessFactors and store it in SAP HR, requirement is to receive a JPG photo in decoded base64 format via CPI as XML payload and then store this employee photo in business object ‘PREL’.
I have followed all the 6 steps mentioned by you for interfacing the document and tried running I don’t get any error in any of the function modules but the photo is also not saving in the business objet PREL can please someone help?
I had similar issue when I tried above code, problem seems to be when the objkey is complete.
Here the example was for SD invoice, VBRK unique key is document number.
Though in my case, the value of object key was Document number+Document year. When passed, the program worked as expected.
FM BINARY_RELATION_CREATE_COMMIT, Exporting param obj_rolea-objkey should be complete key. Try this,
Hi Isuru,
Thanks for your wonderful help and I really appreciate your hard work.
Best Regards,
Vibes
Hi Isuru,
The attachment doesn’t work when trying the BKPF version of the code,
However, the error message doesn’t give any feedback at all to point out what’s wrong.
I think I’m using the wrong object type or key, but i have no way of identifying the error without an error message to start with.
can ask if there is something you can add to put me into the right direction?
Hi Isuru,
Thanks for this, it save me tons of hours for research, trial and error.
but I just need to confirm, this only works for S4 right?
My test program in R3 isnt attaching anything while the one in the S4 system doing ok.
I have to attach a PDF to a PURCHASE ORDER.
It does not work.
Does not throw errors or exceptions.
How do I create the Obj_id.
will that?
Hola, sabes que he implementado tu codigo funciona bien , pero cuando intento subir un archivo excel lo sube con caracteres extraños , es como si faltara algina codificacion, tienes alguna idea que pueda probar?