8

Push S/4 HANA Data Event to BTP Event Mesh in ABAP OO Mode

 10 months ago
source link: https://blogs.sap.com/2023/07/07/push-s-4-hana-data-event-to-btp-event-mesh-in-abap-oo-mode/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Introduction

SAP has provided two native components “Enterprise Event Enablement” and “SAP Netweaver Addon for Event Enablement”. In the document, the component “SAP Netweaver Addon for Event Enablement” will be used.

I have get lots of helps from Zhang, Fiona’s blog post on how to push Data Event from S4 into Event Mesh. Whereas in most cases, the event message will be in deep structure rather than a flat structure. Please go through the rest of section for how to implement it via the framework.

Scope

This is not an end-to-end tutorial. The miss part can be found in Fiona’s blog post.

In scope

  • SAP addon configuration
  • Enhancement implementation

Out  scope

  • Event Mesh configuration
  • BTP service configuration

Prerequisit

  1. BTP Event Mesh is working and Service Key has been generated.
  2. SAP Netweaver Addon for Event Mesh has been installed
  3. RFC Destination to Event Mesh and Token has been configured

if above steps have not been done, please check the details steps in Fiona’s blog post

Implement Steps

In the example below, a purchase order create event is going to raised from S/4 hana. The event has header-item two layers. Different from all of the relevant blog posts using BOR object, the ABAP OO object will be used to raise the event. The effect would be the same. But just introduce a different way.

Create Custom ABAP Class Event

The class should be compatible with SAP business workflow. The implementation steps are exactly the same. If you are familar with the business workflow via ABAP OO, you can ignore this part.

  1. Interface

The class should inherit interface IT_WORKFLOW

01-2.png

2. Attribute

Add two attributes to the class as below. Since the class is for purchase order, the key should be with type EKKO-EBELN

02-3.png

3. Constructor Method

Once the interface has been added, there will few methods inherited from the interface. Please add a custom constructor method

03-2.png

with following source code inside

  METHOD constructor.
    DATA(lv_class_name) = cl_abap_classdescr=>get_class_name( me ).
    SPLIT lv_class_name+1 AT '=' INTO TABLE DATA(lt_class_name).
    me->_por-catid  = lt_class_name[ 1 ].
    me->_por-typeid = lt_class_name[ 2 ].
    me->_por-instid = im_order.
    ME->_key        = im_order.
  ENDMETHOD.

This is how the method looks like

04-2.png

4. Method BI_PERSISTENT~FIND_BY_LPOR

  METHOD bi_persistent~find_by_lpor.
    DATA(lv_order) = CONV ebeln( lpor-instid(10) ).
    result = NEW zcl_purchase_order( lv_order ).
  ENDMETHOD.
05-3.png

5. Method BI_PERSISTENT~LPOR

  METHOD bi_persistent~lpor.
    result = _por.
  ENDMETHOD.
06-1.png

6. Rest of Methods

For rest of methods, just activate them with empty source code.

7. Class Event

Create an event with name on_create. You can make any names making sense. There is no need add any parameters to the event. The event information will not be transfered via the parameter.

07-1.png

Create Virtual Message Type

The message type is a virtune entity used by the framework. Itself doen’t contain any structure information.

use tcode WE81 to create the message type

08-1.png

Activate the message type via BD50

09.png

Create Event Message Structure

This  is the place define the event message structure. This is the structure of purchase order header. in order to make everything simple, it just contains order id and header text. Item field’s type is a table type so that it can be an array in the runtime.

10-7.png

This is the item structure. Remember, once create it, please create a table type referring this basic structure, which will be used in the header struture for item type.

Picture11-1.png

now the structure will have two layers.

Link Change Document Object to Custom Event

tcode: SWEC

The mechanism of ‘SAP Netweaver Addon for Event Enablement’ is triggered via the ‘Change Document Object’. here we link the change document object of purchase order creation to the custom event create just now.

The change document object for purchase order is: EINKBELEG

Picture12-1.png

tip: please search table TCDOB for relevant change document object. Furthermore you can create your own custom change document object for your specific requirement.

Configure Replicate Object

This is the main configuration of the component ‘SAP Netweaver Addon for Event Enablement’.

Spro –> integration with other SAP component –> SAP Netweaver AddOn for Event enablement –> connection and Replication Object Custominzing

Picture13-1.png
  1. Connection Instance

Please record the name of instance. Here BTP_EVENT_MESH has been used. It will be used later. For the RFC destination configuration, please check Fiona’s blog post.

Picture14.png

2. Outbound Object

Fill the value as below

Picture15.png

Explain:

  1. Object name is PO_CREATE. Please record it since it will be used in the filter later.
  2. The SAP native extractor FM for Data Event is /ASADEV/ACI_GEN_VIEW_EXTRACTOR. However this guy can only handle view, which is a flat structure. We will create a custom one replacing it. Fill name ZACI_EVENT_EXTRACTOR here.
  3. Virtual Message type
  4. Select as disaplayed
  5. SAP EM
  6. The SAP native format FM for Data Event is /ASADEV/ACI_GEN_VIEWFRM_SAP_EM. Again the limitation of guy is it only work for flat structure. We will create a custom one replacing it. Fill name ZACI_EVENT_TO_JSON here.

3. Configure Header Attributes

ACI_VIEW should be the event message type created just now.

SAP_EM_TOPIC should be the topic configured in the BTP Event Mesh.

Picture16.png

Link Custome Event and Virtual Message Type

tcode SWE2

Receiver Type is the virtual message type created just now.

Receiver FM is /ASADEV/ACI_EVENTS_TRIGGER

Do not forget the check the flag for linkage activation.

Picture16-1.png

tip: the switch for ‘Linkage Activated’ can be used to switch on/off event connection.

Implement Relevant FM of Replicate Object

  1. Format FM zaci_event_to_json

The way to generate json string from ABAP structure is vary. You can develop own way as well. Just to make sure the parameters should be identical.

FUNCTION zaci_event_to_json .
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IR_DATA) TYPE  DATA
*"     VALUE(IV_INSTANCE) TYPE  /ASADEV/AMR_ARIBA_ARIBA_INST
*"     VALUE(IV_OBJECT) TYPE  /ASADEV/AMR_ARIBA_ARIBA_OBJECT
*"  EXPORTING
*"     REFERENCE(ET_CSV_LINES) TYPE  /ASADEV/AMR_TT_CSV_LINE
*"     REFERENCE(ET_RETURN) TYPE  /ASADEV/ACI_TT_BAPIRET2
*"----------------------------------------------------------------------

  DATA:
    lt_csv_lines          TYPE /asadev/amr_tt_csv_line, "
    lt_csv_bundle         TYPE /asadev/amr_tt_csv_line, "
    ls_amr_obj            TYPE /asadev/amr_obj,  "
    ls_csv_line           TYPE LINE OF /asadev/amr_tt_csv_line.

  CONSTANTS:  lc_attr_db_name TYPE /asadev/aci_def_attr VALUE 'ACI_VIEW'.
  FIELD-SYMBOLS: <ft_data>    TYPE ANY TABLE.

  "get the data:
  ASSIGN ir_data->* TO <ft_data>.
  IF sy-subrc NE 0 OR <ft_data> IS INITIAL.
    RETURN.
  ENDIF.

  " convert data into json
  DATA(lv_json) = /ui2/cl_json=>serialize(
       data        = <ft_data>
       pretty_name = /ui2/cl_json=>pretty_mode-low_case ).

  APPEND lv_json to lt_csv_lines.
  ls_amr_obj = /asadev/cl_aci_helper=>get_aci_object(
               iv_instance = iv_instance
               iv_object   = iv_object ).

*MOD-003 bundle as many csv_lines as customized into one cloud event
  LOOP AT lt_csv_lines INTO ls_csv_line.
    APPEND ls_csv_line TO lt_csv_bundle.
    IF lines( lt_csv_bundle ) EQ ls_amr_obj-item_lines.
      " now wrap the payload in the cloudevents header
      CALL FUNCTION '/ASADEV/ACI_SAP_EM_CLOUDEV_FM'
        EXPORTING
          it_csv_lines = lt_csv_bundle
          iv_instance  = iv_instance
          iv_object    = iv_object
        IMPORTING
          et_csv_lines = lt_csv_bundle
          et_return    = et_return.

      APPEND LINES OF lt_csv_bundle TO et_csv_lines.
      IF ls_amr_obj-item_lines GT 0.
        DO ls_amr_obj-item_lines - 1 TIMES.
          APPEND INITIAL LINE TO et_csv_lines.
        ENDDO.
      ENDIF.
      CLEAR lt_csv_bundle.
    ENDIF.
  ENDLOOP.

  "Append the remaining lines
  IF lines( lt_csv_bundle ) GE 1.
    CALL FUNCTION '/ASADEV/ACI_SAP_EM_CLOUDEV_FM'
      EXPORTING
        it_csv_lines = lt_csv_bundle
        iv_instance  = iv_instance
        iv_object    = iv_object
      IMPORTING
        et_csv_lines = lt_csv_bundle
        et_return    = et_return.

    APPEND LINES OF lt_csv_bundle TO et_csv_lines.
    IF ls_amr_obj-item_lines GT 0.
      DO ls_amr_obj-item_lines - 1 TIMES.
        APPEND INITIAL LINE TO et_csv_lines.
      ENDDO.
    ENDIF.
    CLEAR lt_csv_bundle.
  ENDIF.
ENDFUNCTION.

2. Data Retrieving FM zaci_event_extractor

The save above. You can develop your own version as well. 🙂

FUNCTION zaci_event_extractor .
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_INSTANCE) TYPE  /ASADEV/AMR_ARIBA_ARIBA_INST
*"     REFERENCE(IV_OBJECT) TYPE  /ASADEV/AMR_ARIBA_ARIBA_OBJECT
*"     REFERENCE(IT_BDCP_LINES) TYPE  /ASADEV/ACI_TT_BDCP
*"  EXPORTING
*"     REFERENCE(ET_RETURN) TYPE  /ASADEV/ACI_TT_BAPIRET2
*"     REFERENCE(ET_KEY_BDCP) TYPE  /ASADEV/ACI_TT_BDCP_KEY
*"     REFERENCE(ET_TABLE_CONTENT) TYPE  /ASADEV/ACI_TT_TABLE_CONTENT
*"     REFERENCE(ER_DATA) TYPE REF TO  DATA
*"  EXCEPTIONS
*"      NOT_A_VALID_TABLE
*"----------------------------------------------------------------------

  DATA: lo_badi          TYPE REF TO /asadev/aci_gen_extractor_badi,
        ct_table_content TYPE /asadev/aci_tt_table_content,
        lr_dataref_t     TYPE REF TO data.

* Get BAdI instance for extractor enhancements
  /asadev/cl_aci_badi_helpr=>get_extr_badi( 
          EXPORTING 
            iv_instance = iv_instance
            iv_object = iv_object
          CHANGING  
            co_extractor_badi = lo_badi
            ct_return = et_return ).

  IF lo_badi IS BOUND.
    /asadev/cl_aci_badi_helpr=>call_badi_extr_post_exit( 
          EXPORTING 
            io_extractor_badi = lo_badi
            iv_instance = iv_instance
            iv_object = iv_object
            it_bdcp_lines = it_bdcp_lines
          CHANGING 
            ct_table_content = ct_table_content
            ct_return = et_return
            cr_data = lr_dataref_t ).
  ENDIF.

  er_data = lr_dataref_t.
ENDFUNCTION.

3. Implement BAdI /ASADEV/ACI_GEN_EXTR

The data extractor is generic and the concrete extracting logic should be embeded in a certain implementation with a specific filter.

create an implementation for purchase order

Picture17.png

configure the filter for the PO implementation by using the bellowing information. The values should be from the above configuration sections. This will guarentee that only PO create event will be processed by the implmentation.

Picture18.png

Implement method POST_EXIT. The logic depends on what kind of message structure defined. Here is my code

  METHOD /asadev/aci_extrctpr_if~post_exit.
    DATA lr_dataref TYPE REF TO data.
    DATA(lv_order) = CONV ebeln( it_bdcp_lines[ 1 ]-tabkey+35 ). " Get PO number
    DATA:
      ls_data TYPE zpurchase_order.
    FIELD-SYMBOLS:
      <ls_purchase_order> type zpurchase_order,
      <lt_purchase_order> TYPE STANDARD TABLE.
    CREATE DATA lr_dataref TYPE TABLE OF zpurchase_order.
    ASSIGN lr_dataref->* TO <lt_purchase_order>.
    APPEND INITIAL LINE TO <lt_purchase_order> ASSIGNING <ls_purchase_order>.

    SELECT SINGLE *
      FROM ekko
      INTO @DATA(ls_ekko)
     WHERE ebeln EQ @lv_order.

    SELECT *
      FROM ekpo
      INTO TABLE @DATA(lt_ekpo)
     WHERE ebeln EQ @lv_order.

    <ls_purchase_order> = VALUE #(
                order_id    = lv_order
                header_text = ''
               ).
    LOOP AT lt_ekpo ASSIGNING FIELD-SYMBOL(<ls_ekpo>).
      APPEND INITIAL LINE TO <ls_purchase_order>-items ASSIGNING FIELD-SYMBOL(<ls_item>).
      <ls_item>-item_number = <ls_ekpo>-ebelp.
      <ls_item>-item_text   = <ls_ekpo>-txz01.
      <ls_item>-material    = <ls_ekpo>-matnr.
      <ls_item>-quantity    = <ls_ekpo>-menge.
      <ls_item>-uom         = <ls_ekpo>-meins.
    ENDLOOP.

    cr_data = lr_dataref.
  ENDMETHOD.

Unit Test

1. Create a Purchase Order in the system

This is a dummy order created in the system with number 4500000749. It has three items whose quantities are 12, 24 and 56.

20-1.png

2. Event Received in the Event Mesh

The event does contain the order id and three items with correct their information.

19-1.png

Conclusion

  • ABAP oo Event is working for ‘SAP Netweaver Addon for Event Enablement’
  • Deep structure or multi layer can be fulfilled via custom FMs

Questions

During the investiagtion I have come up with a few questions. Hopefully someone can help me.

1. Comparison between two components. “SAP Netweaver Addon for Event Enablement” and “Enterprise Event Enablement”. What are pros and cons of them? Which one is more suitable for what kind of requirement?

2. For CPI connects with BTP Event Mesh, we have Webhook and AMQP. Can I know which way is recommended?

Cheers.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK