Upload Document in SAP Easy DMS using ODATA, SharePoint Online & Microsoft Power Automate

We got an interesting scenario where a product manager wanted to store documents in an SAP Easy DMS.

SAP Easy DMS is a Document Management System that tracks, manages, and stores documents.

Power Automate is a service that helps you create automated workflows between your favourite apps and services to synchronise files, get notifications, collect data, and more.

As we have no direct connectors from Power Automate to SAP Easy DMS, hence we had to build our own ODATA Services in SAP Abap and consume it from Power Automate.

Let us get started

Steps to Create OData to Upload file in SAP

1. Create a structure with field type string to capture data in ODATA service with other required fields as shown below.

2. Create OData service in SEGW using the above Structure (Entity Types & Entity Set). Generate and Activate Services.

3. Redefine Create Method and use the below code sequence.

4. Read data into method

5. Convert Base 64 input data into Xtring

6. Convert XSTRING_TO_BINARY

7. Create document using FM BAPI_DOCUMENT_CREATE2

8. Once document creation is successful use FM CVAPI_DOC_CHECKIN to upload file in Document.

some sample code

DATA : lv_xstring     TYPE xstring,
           lv_op_length   TYPE i,
           lv_doctype     TYPE dokar,
           lv_docnumber   TYPE doknr,
           lv_docpart     TYPE doktl_d,
           lv_docversion  TYPE dokvr,
           ls_return      TYPE bapiret2,
           ls_entity      TYPE zst_dms_doc_upload,
           ls_docdata     TYPE bapi_doc_draw2,
           ls_objectdescr TYPE bapi_doc_drat,
           lt_objectdescr TYPE TABLE OF bapi_doc_drat,
           ls_pdf_checkin TYPE drao,
           lt_pdf_checkin TYPE STANDARD TABLE OF drao,
           ls_files       TYPE cvapi_doc_file,
           lt_files       TYPE STANDARD TABLE OF cvapi_doc_file,
           lt_content     TYPE STANDARD TABLE OF orblk WITH DEFAULT KEY,
           ls_msg         TYPE messages,
           ls_api_control TYPE cvapi_api_control.

    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).

    CALL FUNCTION 'SCMS_BASE64_DECODE_STR'
      EXPORTING
        input  = ls_entity-file_content
      IMPORTING
        output = lv_xstring
      EXCEPTIONS
        failed = 1
        OTHERS = 2.

    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
      EXPORTING
        buffer        = lv_xstring
      IMPORTING
        output_length = lv_op_length
      TABLES
        binary_tab    = lt_content.

    " SET VALUES
    ls_docdata-documenttype     = 'Mention Document Type'.
    ls_docdata-documentversion  = '00'.
    ls_docdata-documentpart     = '000'.
    ls_docdata-laboratory       = '000 '.

    ls_objectdescr-description  = 'Test Document Aditya' && ':' && sy-datum && '-' && sy-uzeit.
    ls_objectdescr-language     = 'E'.
    ls_objectdescr-language_iso = 'EN'.
    APPEND ls_objectdescr TO lt_objectdescr.

    " CREATE ATTACHMENT
    CALL FUNCTION 'BAPI_DOCUMENT_CREATE2'
      EXPORTING
        documentdata         = ls_docdata
      IMPORTING
        documenttype         = lv_doctype
        documentnumber       = lv_docnumber
        documentpart         = lv_docpart
        documentversion      = lv_docversion
        return               = ls_return
      TABLES
        documentdescriptions = lt_objectdescr.


      COMMIT WORK AND WAIT.


* Files Data
    ls_files-filename    = ls_entity-file_name.
    ls_files-storage_cat = ‘Mention Storage Category’.
    ls_files-appnr       = '1'.
    ls_files-dappl       = ls_entity-file_application.    "PDF/WIN
    ls_files-description = ls_entity-file_description.
    ls_files-checked_in  = 'X'.
    ls_files-updateflag  = 'I'.
    APPEND ls_files TO lt_files.

* Control Data
    ls_api_control-no_update_task = 'X'.
    ls_api_control-api_mode       = 'X'.
    ls_api_control-commit_flag    = 'X'.

* Prepare checkin file data.
    LOOP AT lt_content INTO DATA(lw_content).
      ls_pdf_checkin-dokar = lv_doctype.
      ls_pdf_checkin-doknr = lv_docnumber.
      ls_pdf_checkin-dokvr = lv_docversion.
      ls_pdf_checkin-doktl = lv_docpart.
      ls_pdf_checkin-appnr = '1'.
      ls_pdf_checkin-zaehl = sy-tabix.
      ls_pdf_checkin-orln  = lv_op_length.
      ls_pdf_checkin-orblk = lw_content.
      APPEND ls_pdf_checkin TO lt_pdf_checkin.
      CLEAR : ls_pdf_checkin.
    ENDLOOP.

* Wait for 10 seconds
    WAIT UP TO 5 SECONDS.

    CALL FUNCTION 'CVAPI_DOC_CHECKIN'
      EXPORTING
        pf_dokar           = lv_doctype
        pf_doknr           = lv_docnumber
        pf_dokvr           = lv_docversion
        pf_doktl           = lv_docpart
        pf_ftp_dest        = 'SAPFTPA'
        pf_http_dest       = 'SAPHTTPA'
        ps_api_control     = ls_api_control
      IMPORTING
        psx_message        = ls_msg
      TABLES
        pt_files_x         = lt_files
        pt_content         = lt_pdf_checkin.

      COMMIT WORK AND WAIT.


Consume ODATA from Power Automate

Before we did into Power Automate, it is important to mention that we tested the endpoint using Postman and it worked really well – however while automating it using Power Automate, it failed with the following error “CSRF Token Validation Failed”.

I found from this blog that we had to pass the Cookie – from the initial POST while getting the x-csrf token – to the next POST while posting the document; that too in some specific format.

We are going to see all these in detail.

This is how the entire flow looks alike


1. Trigger the flow on a Selected File from SharePoint Online


2. Get file properties


3. Get file content


4. HTTP – GET x-csrf-token

in ODATA, on change requests (PUT, POST, and DELETE) of REST clients to an ABAP server, the client has to provide a CSRF (Cross-Site Request Forgery) token.

Such a token can be retrieved via a previous service call to the ABAP server. For this, first on a none-changing call (GET, HEAD, OPTIONS), the client has to get this token by setting the HTTP header X-CSRF-Token to the value Fetch. A CSRF token is returned by the ABAP server in the same header and can be used for subsequent, server state changing calls using header X-CSRF-Token.

If this header is not present on a server state changing REST call, the server will respond with a HTTP 403 (“Forbidden”) return code, the HTTP header is set to “Required” and an error text (for example, “CSRF token validation failed”) is returned.

The validity of the CSRF token depends on the release of the ABAP component SAP_BASIS and on the activation of the security session management (which is controlled via the transaction SICF_SESSIONS on the granularity of SAP clients):

a) Release < 7.03/7.31 or the security session management is inactive: An own CSRF cookie gets generated (sap-XSRF_<SystemID>_<SAPClient>) and this CSRF token remains valid for 24 hours (86400 seconds).

b) Release >= 7.03/7.31, the validity is bound to the security session, which depends on the system parameter http/security_session_timeout value (see transaction RZ11 for details on this parameter). By default, the security session management is active in these releases.


5. Compose – Base64

base64(outputs(‘Get_file_content’)?[‘body’])


6. Initialize variable – FileName


7. Variable – Set x-csrf-token


8. Variable – Set-Cookie


9. Various compose actions are needed to set the cookie

Compose – Split All
split(variables(‘varSet-Cookie’),’;’)

Compose – Sap-client
split(variables(‘varSet-Cookie’),’;’)[0]

Compose – MYSAPSSO2
split(split(variables(‘varSet-Cookie’),’;’)[1],’,’)[1]

Compose – SAP SESSIONID
split(split(variables(‘varSet-Cookie’),’;’)[4],’,’)[1]

Compose – SPNegoTokenRequested
formatDateTime(utcNow(),’yyyy-MM-dd HH:mm:ss’)

Compose – Postman Cookie Format
concat(outputs(‘Compose_-MYSAPSSO2′),’; ‘,outputs(‘Compose-SAP_SESSIONID’),’; ‘,outputs(‘Compose-SPNegoTokenRequested’),’; ‘,outputs(‘Compose-_Sap-client’))

Compose – Document Extension
split(variables(‘varFileName’),’.’)[1]


10. Check whether the uploaded file is a PDF or an OFFICE File


11. Finally HTTP – POST to SAP Easy DMS


This was an interesting approach to connecting SAP using ODATA from a Microsoft Power Platform.

Hoping to share my knowledge soon.

Thanks for reading this post 🙂

MCT

In the year 2010 when I took MOSS 2007 Training conducted by an MCT who is now my friend – I admired him for being in such a high position – Microsoft Certified Trainers (MCTs) are the premier technical and instructional experts in Microsoft technologies.

I never in my life dreamed that one day I will become a Microsoft Certified Trainer which has provided me with immense satisfaction and I intend to honour that trust from Microsoft.

As an active MCT now, I will get exclusive benefits as an MCT including access to the complete library of official Microsoft training and certification products, substantial discounts on exams, books, and Microsoft products.

In addition, MCTs will be able to use Microsoft readiness resources to help enhance their training career and engage with other MCT members in an online community forum. They will also receive invitations to exclusive Microsoft and local MCT community events.