Skip to Content
Technical Articles
Author's profile photo Jay Malla

Publishing Events from S/4 HANA to Event Mesh for Cloud integration for external systems

Hi SAP Community Folks,

It’s been a few months since I had published a blog.  My last few blogs have been on Fiori development and prior to that, SAP HANA native development.  I joined Delaware Consulting earlier this year and I am working as a Fiori Solution and S/4 HANA integration architect and team lead.

For the past few months, I have been working on an S/4 HANA new implementation leveraging the SAP integration suite – Cloud Integration, Event Mesh, API Hub, Integration advisor, etc.  In this blog, I wanted to capture sending out business transaction events from S/4 HANA to the Event Mesh and having CPI read from the Event Mesh and then process the event, read additional data from S/4 HANA using the OData API to enrich the message, and then publish to an outbound queue for downstream systems.

So the first part is setting up the outbound process.  For these steps, the following blog is an excellent starting point:

How to use SAP S/4HANA Event Enablement with SAP Cloud Platform (EN) written by Makoto Sugishita

 

So we set this up and we were sending sales order creations and changes to the event mesh:

SPRO%20Maintain%20topics

 

Maintain the channel topics for publishing the business events

Channel%20topics%20for%20sales%20order%20creation%20and%20changes

 

Then we create the queue in Event Mesh and the queue subscription to subscribe to the sales order create and change events:

 

 

For our testing, we used the SAP transaction code SWUE to trigger the sales order event to send to the queue.  Once this is all set up, the events will be triggered automatically when creating or changing a sales order:

 

Transaction%20SWUE%20to%20trigger%20sales%20order%20creation%20event

Transaction SWUE to trigger sales order creation event

 

Transaction%20SWUE%20to%20trigger%20sales%20order%20created

Transaction SWUE to trigger sales order created

 

Here are the sales order in the queue:

 

Queue%20with%20sales%20order%20events

Queue with sales order events

 

 

So once we receive the sales order business transaction events in the queue, we can then read the queue and process the message to enhance the details through the OData call to S/4 HANA and publish on an outbound queue.

 

Here is the IFlow:

SalesOrderEventFromQ%20IFlow

SalesOrderEventFromQ IFlow

 

AMQP%20General%20tab%20for%20reading%20queue

AMQP General tab for reading queue

 

AMQP%20Connection%20tab%20for%20reading%20queue

AMQP Connection tab for reading queue

AMQP%20Processing%20tab%20for%20reading%20queue

AMQP Processing tab for reading queue

 

Here is the Groovy script to extract the sales order number:

 

// Extract the SALESORDER from the Business Transaction Event


import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.json.*

def Message processData(Message message) {
    def json = new JsonSlurper().parseText(message.getBody(String));
    message.setHeader('SALESORDER',json.data.KEY[0].SALESORDER);
    message.setHeader('eventType',json.eventType);

    return message;
}

 

Here we log the business transaction event with the sales order number we extracted:

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;

def Message processData(Message message) {

   def map = message.getHeaders();
   def salesorder = map.get("SALESORDER");
   def eventType = map.get("eventType");

   
   def body = message.getBody(java.lang.String) as String;
   def messageLog = messageLogFactory.getMessageLog(message);


    //Properties
    def properties = message.getProperties();
    
   String sBody = "SalesOrder " + salesorder  + " Event " + eventType + " from S4 HANA";


   if(messageLog != null) {
       messageLog.setStringProperty(sBody, body);
       messageLog.addAttachmentAsString(sBody, body, 'application/json');
    }

   return message;
}

 

Here is the Request-Reply to call the OData sales order API to get the order details:

OData%20General%20tab

OData General tab

OData%20connection%20tab

OData connection tab

 

OData%20processing%20tab

OData processing tab

 

Here is the Log SAP OData XML Response:

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;

def Message processData(Message message) {

   def map = message.getHeaders();
   def salesorder = map.get("SALESORDER");
   
   def body = message.getBody(java.lang.String) as String;
   def messageLog = messageLogFactory.getMessageLog(message);

    //Properties
    def properties = message.getProperties();
    
   String sBody = "OData SalesOrder " + salesorder + " Details XML from S4 HANA";


   if(messageLog != null) {
       messageLog.setStringProperty(sBody, body);
       messageLog.addAttachmentAsString(sBody, body, 'text/xml');
    }

   return message;
}

 

Here is the Log SAP OData JSON Response:

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;

def Message processData(Message message) {

   def map = message.getHeaders();
   def salesorder = map.get("SALESORDER");
   
   def body = message.getBody(java.lang.String) as String;
   def messageLog = messageLogFactory.getMessageLog(message);

    //Properties
    def properties = message.getProperties();
    
   String sBody = "OData SalesOrder " + salesorder + " Details JSON from S4 HANA";


   if(messageLog != null) {
       messageLog.setStringProperty(sBody, body);
       messageLog.addAttachmentAsString(sBody, body, 'application/json');
    }

   return message;
}

 

And here is the final publishing to the outbound queue:

 

AMQP%20General%20tab%20for%20writing%20to%20queue

AMQP General tab for writing to queue

 

AMQP%20Connection%20tab%20for%20writing%20to%20queue

AMQP Connection tab for writing to queue

 

AMQP%20Processing%20tab%20for%20writing%20to%20queue

AMQP Processing tab for writing to queue

 

So once the event is written to the queue and the Flow is triggered, then you can see the following messages in the integration message monitoring:

 

Message%20monitoring

Message monitoring

 

Here is how the event json looks like:

SalesOrder 0000000494 Event BO.SalesOrder.Created from S4 HANA

{
  "eventType": "BO.SalesOrder.Created",
  "cloudEventsVersion": "0.1",
  "source": https://sap.corp,
  "eventID": "AvI8lTL3HuyLryFqiGugrw==",
  "eventTime": "2021-10-15T05:30:44Z",
  "schemaURL": https://sap.corp/sap/opu/odata/IWXBE/BROWSER_SRV/,
  "contentType": "application/json",
  "data": {
    "KEY": [
      {
        "SALESORDER": "0000000494"
      }
    ]
  }
}

 

 

OData SalesOrder 0000000494 Details XML from S4 HANA

<A_SalesOrder>
  <A_SalesOrderType>
    <CreationDate>2021-10-21T00:00:00.000</CreationDate>
    <CreatedByUser>YTHAM</CreatedByUser>
    <OrganizationDivision>00</OrganizationDivision>
    <PurchaseOrderByCustomer>YT_ODN_AU</PurchaseOrderByCustomer>
    <DistributionChannel>10</DistributionChannel>
    <SalesOrganization>3010</SalesOrganization>
    <SoldToParty>30100001</SoldToParty>
    <TotalNetAmount>120.00</TotalNetAmount>
    <to_Item>
      <A_SalesOrderItemType>
        <SalesOrderItemText>Service Material 01</SalesOrderItemText>
        <ProductionPlant>3010</ProductionPlant>
        <PurchaseOrderByCustomer>YT_ODN_AU</PurchaseOrderByCustomer>
        <Material>SM0001</Material>
        <MaterialByCustomer>
        </MaterialByCustomer>
        <RequestedQuantityUnit>H</RequestedQuantityUnit>
        <TransactionCurrency>AUD</TransactionCurrency>
        <PricingDate>2021-10-21T00:00:00.000</PricingDate>
        <NetAmount>120.00</NetAmount>
        <SalesOrderItemCategory>TAD</SalesOrderItemCategory>
        <SalesOrderItem>10</SalesOrderItem>
        <HigherLevelItem>0</HigherLevelItem>
        <RequestedQuantity>1.000</RequestedQuantity>
        <SalesOrder>494</SalesOrder>
      </A_SalesOrderItemType>
    </to_Item>
    <TransactionCurrency>AUD</TransactionCurrency>
    <SalesOrderType>OR</SalesOrderType>
    <SalesOrderDate>2021-10-21T00:00:00.000</SalesOrderDate>
    <to_Partner>
      <A_SalesOrderHeaderPartnerType>
        <PartnerFunction>SP</PartnerFunction>
        <Customer>30100001</Customer>
        <Supplier>
        </Supplier>
        <Personnel>0</Personnel>
        <ContactPerson>0</ContactPerson>
        <SalesOrder>494</SalesOrder>
      </A_SalesOrderHeaderPartnerType>
      <A_SalesOrderHeaderPartnerType>
        <PartnerFunction>BP</PartnerFunction>
        <Customer>30100001</Customer>
        <Supplier>
        </Supplier>
        <Personnel>0</Personnel>
        <ContactPerson>0</ContactPerson>
        <SalesOrder>494</SalesOrder>
      </A_SalesOrderHeaderPartnerType>
      <A_SalesOrderHeaderPartnerType>
        <PartnerFunction>PY</PartnerFunction>
        <Customer>30100001</Customer>
        <Supplier>
LanguageHTML/XML

        </Supplier>
        <Personnel>0</Personnel>
        <ContactPerson>0</ContactPerson>
        <SalesOrder>494</SalesOrder>
      </A_SalesOrderHeaderPartnerType>
      <A_SalesOrderHeaderPartnerType>
        <PartnerFunction>SH</PartnerFunction>
        <Customer>30100001</Customer>
        <Supplier>
        </Supplier>
        <Personnel>0</Personnel>
        <ContactPerson>0</ContactPerson>
        <SalesOrder>494</SalesOrder>
      </A_SalesOrderHeaderPartnerType>
    </to_Partner>
    <SalesOrder>494</SalesOrder>
  </A_SalesOrderType>
</A_SalesOrder>


OData SalesOrder 0000000494 Details JSON from S4 HANA

{
  "A_SalesOrder": {
    "A_SalesOrderType": {
      "CreationDate": "2021-10-21T00:00:00.000",
      "CreatedByUser": "YTHAM",
      "OrganizationDivision": "00",
      "PurchaseOrderByCustomer": "YT_ODN_AU",
      "DistributionChannel": "10",
      "SalesOrganization": "3010",
      "SoldToParty": "30100001",
      "TotalNetAmount": "120.00",
      "to_Item": {
        "A_SalesOrderItemType": {
          "SalesOrderItemText": "Service Material 01",
          "ProductionPlant": "3010",
          "PurchaseOrderByCustomer": "YT_ODN_AU",
          "Material": "SM0001",
          "MaterialByCustomer": "",
          "RequestedQuantityUnit": "H",
          "TransactionCurrency": "AUD",
          "PricingDate": "2021-10-21T00:00:00.000",
          "NetAmount": "120.00",
          "SalesOrderItemCategory": "TAD",
          "SalesOrderItem": "10",
          "HigherLevelItem": "0",
          "RequestedQuantity": "1.000",
          "SalesOrder": "494"
        }
      },
      "TransactionCurrency": "AUD",
      "SalesOrderType": "OR",
      "SalesOrderDate": "2021-10-21T00:00:00.000",
      "to_Partner": {
        "A_SalesOrderHeaderPartnerType": [
          {
            "PartnerFunction": "SP",
            "Customer": "30100001",
            "Supplier": "",
            "Personnel": "0",
            "ContactPerson": "0",
            "SalesOrder": "494"
          },
          {
            "PartnerFunction": "BP",
            "Customer": "30100001",
            "Supplier": "",
            "Personnel": "0",
            "ContactPerson": "0",
            "SalesOrder": "494"
          },
          {
            "PartnerFunction": "PY",
            "Customer": "30100001",
            "Supplier": "",
            "Personnel": "0",
            "ContactPerson": "0",
            "SalesOrder": "494"
          },
          {
            "PartnerFunction": "SH",
            "Customer": "30100001",
            "Supplier": "",
            "Personnel": "0",
            "ContactPerson": "0",
            "SalesOrder": "494"
          }
        ]
      },
      "SalesOrder": "494"
    }
  }
}

 

Lastly, I wanted to add some troubleshooting tips.  When we first configured the outbound topic, the events were not being sent out to the message queue.  So we had to create a ticket for SAP and we were told that the entries:

The issue is because of 2 wrong entries maintained in the table SBO_I_BODEF for Sales Order. Please find the attached screenshot.

Wrong Entries:

SALES ORDER BO BUS2032

SALES ORDER SOA 114

 

Expected Entries:

SalesOrder BO BUS2032

SalesOrder CL CL_SD_SALESORDER_WORKFLOW

SalesOrder SOA 114

Expected entries are there in the table. Since there are wrong entries also present in the table for the same Business Object, events are not getting passed. Please remove those entries and retest the issue.

 

Maintain Customizing settings under

SAP NetWeaver->Application Server->Business Management->SAP Object Type Repository->SAP Object Types->Maintain Object Representation

 

SPRO%20-%20Maintain%20object%20representation

SPRO – Maintain object representation

 

Make sure the following entries are there for BUS2032.  There should not be another set of entries there for BUS2032:

 

Sales%20order%20entries%20in%20object%20representation

Sales order entries in object representation

Hopefully, this will help if you are embarking on the journey of publishing events from S/4 HANA to downstream subscribers.  Though this is the evolution of SAP integration with events and OData, the IDoc and SOAP async approaches still are widely used and maybe the better choice given the scenarios.  After having set up IDoc integration and SOAP integration through PI/PO for many projects, the new event mesh approach is a nice option to have also in the wide array of SAP integration methodolgies.  Happy learning!

Thanks,

Jay

 

 

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Senthilkumar Moorthy
      Senthilkumar Moorthy

      Excellent Blog. It is very interesting to see how the Event Driven Architecture is evolving in S4.

      Regards

      Senthil.

      Author's profile photo Jay Malla
      Jay Malla
      Blog Post Author

      Thanks Senthil.  If we can send the OData with the event, then it would save the round trip call to S/4.  Then we can leverage it similar to the outbound IDoc approach that has been tried and true since the inception.

      Regards,

      Jay