Monday, 6 December 2021

Posting the data to BW4HANA ADSO using BW APIs and RFC connection

Problem introduction

As a developer, you would like to expose a service that enables third-party APIs to post the data directly into SAP BW ADSO.

For that reason, you would like to use an RFC enabled BW function module that allows the external source like CPI to read BW parameters, request the data from an outside source through REST, harmonize it and post the data to BW ADSO in a columnar format.

Use-case description

Business

You would like to show the planned FTE per Cost Center. You would like to include a distinction per employee joining the company, leaving, and moving the Cost Centers. You would like to refresh the data if the change is made retroactively.

Technical

A sample below is to acquire the data from a time-dependent Workday report with DateFrom and DateTo parameters for multiple periods at once and to post the result to BW.

You would like to read the data from a Workday report using CPI, REST, and passing different parameters for each request. From CPI, you call a BW Function Module to receive the parameters for the request. You receive multiple sets of parameters to run the Workday report with.

Then, based on the Workday connection, you call Workday report as many times as there are parameters received from BW. You make the requests synchronously, transform them to ABAP input structure via a Groovy script, union them together, and post to BW.

BW4HANA setup

ETL requirement

The data from Workday has to be passed for all the months for which we expect deltas in one request. The Workday report is time-dependent; the FTE data represents employees joining the company, leaving, and shifting Cost Centers for each month.

Setup

CPI calls BW FM through an RFC connection set up in the Cloud Connector. It receives the parameters. CPI calls the BW function module to post the collected data back. Function Module writes the data to an ADSO and runs the process chain to process the data from acquisition to propagation layer.

ADSOs

BW ADSOs with snapshot support enabled are used for the data acquisition layer. It ensures that time-dependent full loads per period are correctly refreshed, and removed transactions no longer exist.

A standard BW ADSO with changelog enabled is used for the propagation layer. It stores the history for the no longer refreshed periods.

SAP ABAP Exam Prep, SAP ABAP Tutorial and Materials, SAP ABAP Tutorial and Materials, SAP ABAP Career, SAP ABAP Skill, SAP ABAP Jobs, SAP ABAP Preparation

Period and employee ID are used as table keys. If a user is present at two Cost Centers at once within the same period because he shifts, then a new record is created on the fly using a table function. A derivation of the status to indicate if an employee changed cost center is made by comparing previous and current Cost Center. SQL solution reference: https://stackoverflow.com/questions/67070499/sql-lag-distinct-to-the-previous-different-value

DTPs

A DTP from the first to the second layer processes the data only for the periods refreshed by the source and needed for the transformation logic. The selection can happen in the DTP routine or the BW user-exit variables.

Transformation

Additional logic is added to decide which employees changed the Cost Center retroactively and post those changes in the current month instead of the past.

Function Modules

Now, back to the main topic of the blog. SAP offers the following APIs to post the data back to BW:

The following APIs are available for a standard DataStore object with the property Write Change Log:

Type Target Table  API for Local Use API for RFC Use  Description 
Load Inbound Table RSDSO_WRITE_API RSDSO_WRITE_API_RFC  Loads data from an internal table to the inbound table. The activation can then be started.
Activate  Active Data  RSDSO_ACTIVATE_REQ_API_RFC  RSDSO_ACTIVATE_REQ_API_RFC  Activates loaded requestsc 

The following APIs are available for a DataStore object for direct updates (Direct Update DataStore object):

Type Target Table  API for Local Use API for RFC Use  Description 
Load

Active Data

RSDSO_DU_WRITE_API RSDSO_DU_WRITE_API_RFC Loads data from an internal table into the active data table.
Delete Active Data  RSDSO_DU_DELETE_API_RFC RSDSO_DU_DELETE_API_RFC

Deletes data from the table of active data. The table of active data can be truncated or selectively deleted.

 

Status Active Data

RSDSO_DU_CLEANUP_API_RFC

RSDSO_DU_CLEANUP_API_RFC

Deletes API requests with errors. Red requests block further load requests by DTP or by API.


The selection is made based on the BW requirements. For example, the acquisition layer ADSO is not of the direct-update type, and we would like to write the data to ADSO inbound table using a wrapper RFC enabled FM. We expect the data to be already in the columnar format and not a string. We would like to validate this data upon activation in BW. It also allows easy debugging of incoming RFC requests.

This brings us down to the option for the function module RSDSO_WRITE_API.

1. Create a wrapper Function Module.

It needs to throw errors like the API provided by SAP and add errors if a process chain has failed.
It needs to have an input structure of the active Table of the target ADSO. Please note this table has a record mode field after the key specification. Therefore, it should always be posted as empty.
The function module needs to pass multiple parameters to CPI.

FUNCTION Z_RSDSO_WRITE_API_LEAVER_HIRE
  IMPORTING
    VALUE(IT_DATA) TYPE ZTY_<ADSONAME>1 OPTIONAL
  EXPORTING
    VALUE(ET_PARAMS) TYPE ZTT_<2columns_table_type>
    VALUE(E_LINES_INSERTED) TYPE INT4
    VALUE(E_COLD_LINES_INSERTED) TYPE INT4
    VALUE(ET_MSG) TYPE RS_T_MSG
    VALUE(E_UPD_REQ_TSN) TYPE RSPM_REQUEST_TSN
    VALUE(ET_ACT_REQ_TSN) TYPE RSDSO_T_TSN
  EXCEPTIONS
    WRITE_FAILED
    ACTIVATION_FAILED
    DATASTORE_NOT_FOUND
    CHAIN_FAILED.

<Content>

ENDFUNCTION.​

2. Add a check if the parameters are filled and if the CPI request has data.

FUNCTION Z_RSDSO_WRITE_API_LEAVER_HIRE
  IMPORTING
    VALUE(IT_DATA) TYPE ZTY_DH_AD281 OPTIONAL
  EXPORTING
    VALUE(ET_PARAMS) TYPE ZTY_CHAR10_2COL
    VALUE(E_LINES_INSERTED) TYPE INT4
    VALUE(E_COLD_LINES_INSERTED) TYPE INT4
    VALUE(ET_MSG) TYPE RS_T_MSG
    VALUE(E_UPD_REQ_TSN) TYPE RSPM_REQUEST_TSN
    VALUE(ET_ACT_REQ_TSN) TYPE RSDSO_T_TSN
  EXCEPTIONS
    WRITE_FAILED
    ACTIVATION_FAILED
    DATASTORE_NOT_FOUND
    CHAIN_FAILED.

  CONSTANTS: lc_adso_open_pos TYPE rsoadsonm VALUE '<ADSO_NAME>',
             lc_pc_id         TYPE rspc_chain VALUE '<PC_NAME>'.

    SELECT
       start_date,
       end_date
    FROM
      <parameters_table>
    INTO TABLE
      @et_params.

  IF it_data[] IS NOT INITIAL AND et_params[] IS NOT INITIAL.

  ENDIF.

ENDFUNCTION.​

3. Add executions of the RSDSO_WRITE_API.

It enables the new master data values (sid generation) specification via a parameter i_allow_new_sids.
In addition, it allows specification of whether the data is activated after posting via a parameter

i_activate_data.

It returns a full activation log and the number of inserted & activated lines.
FUNCTION Z_RSDSO_WRITE_API_LEAVER_HIRE
  IMPORTING
    VALUE(IT_DATA) TYPE ZTY_<ADSO_NAME> OPTIONAL
  EXPORTING
    VALUE(ET_PARAMS) TYPE ZTY_CHAR10_2COL
    VALUE(E_LINES_INSERTED) TYPE INT4
    VALUE(E_COLD_LINES_INSERTED) TYPE INT4
    VALUE(ET_MSG) TYPE RS_T_MSG
    VALUE(E_UPD_REQ_TSN) TYPE RSPM_REQUEST_TSN
    VALUE(ET_ACT_REQ_TSN) TYPE RSDSO_T_TSN
  EXCEPTIONS
    WRITE_FAILED
    ACTIVATION_FAILED
    DATASTORE_NOT_FOUND
    CHAIN_FAILED.

  CONSTANTS: lc_adso_open_pos TYPE rsoadsonm VALUE '<ADSO_NAME>',
             lc_pc_id         TYPE rspc_chain VALUE '<PC_NAME>'.

    SELECT
       start_date,
       end_date
    FROM
      <parameters_table>
    INTO TABLE
      @et_params.

  IF it_data[] IS NOT INITIAL AND et_params[] IS NOT INITIAL.

    CALL FUNCTION 'RSDSO_WRITE_API'
      EXPORTING
        i_adsonm              = lc_adso_open_pos
        i_allow_new_sids      = rs_c_true
        i_activate_data       = rs_c_true
        it_data               = it_data
      IMPORTING
        e_lines_inserted      = e_lines_inserted
        e_cold_lines_inserted = e_cold_lines_inserted
        et_msg                = et_msg
        e_upd_req_tsn         = e_upd_req_tsn
        et_act_req_tsn        = et_act_req_tsn
      EXCEPTIONS
        write_failed          = 1
        activation_failed     = 2
        datastore_not_found   = 3
        OTHERS                = 4.
    CASE sy-subrc.

ENDFUNCTION.

4. Add error handling and a process chain execution; below is a basic example.

FUNCTION Z_RSDSO_WRITE_API_LEAVER_HIRE
  IMPORTING
    VALUE(IT_DATA) TYPE ZTY_<ADSO_NAME> OPTIONAL
  EXPORTING
    VALUE(ET_PARAMS) TYPE ZTY_CHAR10_2COL
    VALUE(E_LINES_INSERTED) TYPE INT4
    VALUE(E_COLD_LINES_INSERTED) TYPE INT4
    VALUE(ET_MSG) TYPE RS_T_MSG
    VALUE(E_UPD_REQ_TSN) TYPE RSPM_REQUEST_TSN
    VALUE(ET_ACT_REQ_TSN) TYPE RSDSO_T_TSN
  EXCEPTIONS
    WRITE_FAILED
    ACTIVATION_FAILED
    DATASTORE_NOT_FOUND
    CHAIN_FAILED.

  CONSTANTS: lc_adso_open_pos TYPE rsoadsonm VALUE '<ADSO_NAME>',
             lc_pc_id         TYPE rspc_chain VALUE '<PC_NAME>'.

    SELECT
       start_date,
       end_date
    FROM
      <parameters_table>
    INTO TABLE
      @et_params.

  IF it_data[] IS NOT INITIAL AND et_params[] IS NOT INITIAL.

    CALL FUNCTION 'RSDSO_WRITE_API'
      EXPORTING
        i_adsonm              = lc_adso_open_pos
        i_allow_new_sids      = rs_c_true
        i_activate_data       = rs_c_true
        it_data               = it_data
      IMPORTING
        e_lines_inserted      = e_lines_inserted
        e_cold_lines_inserted = e_cold_lines_inserted
        et_msg                = et_msg
        e_upd_req_tsn         = e_upd_req_tsn
        et_act_req_tsn        = et_act_req_tsn
      EXCEPTIONS
        write_failed          = 1
        activation_failed     = 2
        datastore_not_found   = 3
        OTHERS                = 4.
    CASE sy-subrc.
      WHEN 0.

        CALL FUNCTION 'RSPC_API_CHAIN_START'
          EXPORTING
            i_chain = lc_pc_id.

        IF sy-subrc <> 0.
          MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 RAISING chain_failed.
        ENDIF.

      WHEN 1.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 RAISING write_failed.
      WHEN 2.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 RAISING activation_failed.
      WHEN 3.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 RAISING datastore_not_found.
    ENDCASE.

  ENDIF.

ENDFUNCTION.​

In this example, the CPI request should have the following structure:

<Z_RSDSO_WRITE_API_LEAVER_HIRE>
    <INPUT>
        <IT_DATA>
            <item>
                <key_field>value</key_field>
                <RECORDMODE></RECORDMODE>
                <field>value</field>
            </item>
        </IT_DATA>
</Z_RSDSO_WRITE_API_LEAVER_HIRE>

Result


The data acquired by CPI or any other ABAP-based application can be easily pasted into BW ADSO and processed further.

No comments:

Post a Comment