Use LSMW to Attach GOS Files to Documents
Generic Object Services or GOS is a commonly-used technology from SAP that creates a uniform way to add functionality across various business objects in SAP. One of the functions is a feature that allows attaching a file to a business object such as a document.
As one might expect, the GOS button vanishes when the program used to create a business object is run in batch mode making it useless for a recording. Additionally, the ABAP debugger is useless as the system stops debugging as soon as the GOS button is clicked, so chasing the code rabbit down the programming hole becomes much harder.
Necessity breeds innovation
The example here was born of necessity for a client in Indiana that had a requirement to attach files that were uncompressed from the client's legacy Siebel CRM system, but not even the filenames--much less the files--were provided as source data. In order to develop the tool, some data was dummied up for testing purposes.
The first step is to define the variables used to hold the data that will be passed through the interfaces of the functions. The p_Folder
parameter is hard coded with the presumption that the uncompressed files will be extracted directly to a directory on the network represented by UNC instead of being passed through a SharePoint server.
parameters: p_Break as checkbox, p_Verbos as checkbox default 'X', p_Folder type string default '\\Pnts044042\sap_project\SM\Work\Files'. data: wa_QMEL like QMEL. data: lQMNUM type SWOTOBJID-OBJKEY. " like QMEL-QMNUM. TYPES : BEGIN OF ty_table, "Structure for FileName FNAME(128) TYPE c, END OF ty_table. data: wa_Attachement TYPE BORIDENT, "BOR Identifier workarea ws_BORIDENT TYPE BORIDENT, "BOR Identifier wa_SOOD4 TYPE SOOD4, lFolder TYPE SOODK, it_Files type standard table of ty_table, wa_Files type ty_table, w_h_data TYPE SOOD2, w_fol_data TYPE SOFM2, w_rec_data TYPE SOOS6, it_Connections type standard table of BDN_CON, wa_Connections type BDN_CON, lFileDescription(128) type c, isLoaded(1) type c.
The break point is added in the BEGIN_OF_PROCESSING code block of LSMW. This launches the debugger for testing purposes and allows for break points to be added to the other code blocks during development.
if p_break eq 'X'. break-point. endif.
Next, in the BEGIN_OF_TRANSACTION
, the system validates the Service Notification number and reports if it has not been created. There is little point in uploading the file to SAP before there is a document to attach it to.
If the document does exist then the BDS_GOS_CONNECTIONS_GET
function is called and the returned internal table is looped through to ensure that no duplicates are created. This also enables delta loads to be performed without any additional effort.
isLoaded = ' '. clear: wa_Files, ws_BORIDENT, wa_SOOD4, lFolder, w_h_data, w_fol_data, w_rec_data. refresh: it_Files, it_Connections. concatenate 'S' IW52S-QMNUM+2(10) into lQMNUM. select single * from QMEL into wa_QMEL where QMNUM eq lQMNUM. if sy-subrc ne 0. if p_verbos eq 'X'. write: / IW52S-QMNUM color col_negative, 'Not created.'. endif. else. concatenate IW52S-ATTACHMENTNAME '.' IW52S-TYPE into lFileDescription. "Use this to check if file already attached. call function 'BDS_GOS_CONNECTIONS_GET' exporting CLASSNAME = 'BUS2080' OBJKEY = lQMNUM tables GOS_CONNECTIONS = it_Connections. loop at it_Connections into wa_Connections. if wa_Connections-DESCRIPT eq lFileDescription. isLoaded = 'X'. "File is already attached! if p_verbos eq 'X'. write: / IW52S-QMNUM, lFileDescription(20) color col_positive, 'file already attached.'. endif. endif. endloop.
Next, the program gets the folder where the file will be stored and uses that to populate the lFolder
variable. It isn't clear exactly where this is or how the system stores the file, but it does really matter as most of SAP is abstracted from the underlying data storage media.
if isLoaded ne 'X'. CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET' EXPORTING REGION = 'B' IMPORTING FOLDER_ID = lFolder EXCEPTIONS OTHERS = 1.
With the abstracted folder location in hand, the system now attempts to read the file from the UNC on the Windows network. The SO_DOCUMENT_REPOSITORY_MANAGER
function is called which, in turn, calls dozens of other esoteric functions and methods to read a file from the local PC and store it in the folder location provided.
concatenate p_folder '\' IW52S-ATTACHMENTNAME '.' IW52S-TYPE into wa_Files-FNAME. append wa_Files TO it_Files. wa_SOOD4-FOLTP = lFolder-OBJTP. wa_SOOD4-FOLYR = lFolder-OBJYR. wa_SOOD4-FOLNO = lFolder-OBJNO. wa_SOOD4-OBJDES = lFileDescription. wa_SOOD4-OBJNAM = lFileDescription. w_h_data-objdes = lFileDescription. CALL FUNCTION 'SO_DOCUMENT_REPOSITORY_MANAGER' EXPORTING METHOD = 'IMPORTFROMPC' REF_DOCUMENT = wa_SOOD4 TABLES FILES = it_Files CHANGING DOCUMENT = wa_SOOD4 HEADER_DATA = w_h_data FOLMEM_DATA = w_fol_data RECEIVE_DATA = w_rec_data.
If the file was successfully read and stored in the abstracted folder location then the OKCODE
in the wa_SOOD4
will either be 'CREA' or 'CHNG'. When successful, a few more variables are populated and the BINARY_RELATION_CREATE_COMMIT
function is called with those variables to create the relationship between the document and the file of type ATTA.
The skip_transaction
at the end is there because this example is using LSMW as a wrapper for a BAPI. This can be done just as easily as a report in SE38, but dealing with a BASIS team for transports to production when LSMW is available seems pointless.
if wa_SOOD4-OKCODE = 'CREA' or wa_SOOD4-OKCODE = 'CHNG'. ws_BORIDENT-objkey = wa_QMEL-QMNUM. "Service Notification ws_BORIDENT-objtype = 'BUS2080'. "Business Class wa_Attachement-OBJTYPE = 'MESSAGE'. wa_Attachement-OBJKEY = wa_SOOD4(34). CALL FUNCTION 'BINARY_RELATION_CREATE_COMMIT' EXPORTING OBJ_ROLEA = ws_BORIDENT OBJ_ROLEB = wa_Attachement RELATIONTYPE = 'ATTA' EXCEPTIONS NO_MODEL = 1 INTERNAL_ERROR = 2 UNKNOWN = 3 OTHERS = 4. IF sy-subrc <> 0. if p_verbos eq 'X'. write: / IW52S-QMNUM, lFileDescription color col_negative, 'Was not attached to the document, error #', sy-subrc. endif. ENDIF. else. if p_verbos eq 'X'. write: / IW52S-QMNUM, wa_Files-FNAME color col_negative, 'File was not uploaded.'. endif. endif. "wa_SOOD4-okcode = 'CREA' or wa_SOOD4-okcode = 'CHNG'. endif. "IsLoaded ne 'X'. endif. skip_transaction. "Just using LSMW as wrapper for BAPIs.
The end result
In the image below, the first file was attached on 06/05/2017 using the button while running the IW52 transaction in normal mode. The second document dated 06/06/2017 was loaded using the code above and this dummy data.
Attachment Row Id Row Id - Primary Key Activity Id - Foreign Key SR # Comments Attachment Name Size (In Bytes) Type Modified Update File 1-106W6 1-106W3 1-106W3 1-99998TEST 1-99998TEST 37623 jpg 8/6/2001 2:37:10 PM Y
Identifying the object type for other business objects
It would seem a safe bet that any business object that appears with the GOS button can have files attached using this code, but it may not be clear what OBJTYPE
should be bundled with a document number (OBJKEY
) to be passed in as the OBJ_ROLEA parameter of the BINARY_RELATION_CREATE_COMMIT
function.
A quick search of the TOJTB
table might be enough, but experimentation and some debugging might be required. The BDS_GOS_CONNECTIONS_GET
function is a great place to start digging once a test document has been created with an attached file in the development sandbox . . .
CREDIT
This was a particularly difficult task as there is very little supportive documentation on the internet for it. This programmer owes a great deal of humility and respect to HariKrishna Malladi for providing an explanation of how to use the functions above in this great blog post.