Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
AbinashNanda
Product and Topic Expert
Product and Topic Expert
Aim of this blog is to show how to extend standard integration Content for SAP Sales Cloud an SAP Service Cloud V2.

To get an overview of why extensions are needed, please refer to blog Extending standard integration flow to support Customer extensions – Part I.

SAP Sales Cloud and SAP Service Cloud Version2 uses JSON format for exchanging messages with external systems. As of now standard integration contents are offered for integration of master and transactional data with other SAP Products such as SAP S/4HANA, SAP ERP etc.

On SAP S/4HANA or SAP ERP systems the data format for data exchange is mainly based on XML (SOAP, ODATA, IDOC).

The standard (pre-packaged) content use either message mapping, groovy script or a combination of both to map the data formats between systems, which is either XML->JSON or JSON->XML.

Since data formats are different these cannot be combined as a multi mapping message (which only supports combining messages for one data format), we need a different way of extending the standard content for customer specific requirements.

To achieve this the main integration flow passes source message in a message header and mapped output message as body to exit integration flow via process direct adapter.

Let's use the integration flow Replicate Product from SAP S4HANA as an example to understand the flow of processing in detail

This integration flow replicates material master data from SAP S/4HANA to SAP Sales and Service Cloud V2.

The messages are sent via SOAP (XML) to SAP Cloud Integration where conversion happens to JSON format and delivered to target system.


The integration flow offers a parameter (Custom Exit) which decides a custom extension is needed or not. If the value is set to true, then the source payload is saved to a message header property and call to exit flow happens via the process direct adapter.

Example of an extension iFlow:


Here groovy script is used to enrich the message. The sample code snippet is as below:
def Message productReplicationExit(Message message) {

def body = message.getBody(java.io.Reader)
def json = new JsonSlurper().parse(body)

def xmlString = message.getHeader("sourcePayload",java.io.Reader)

def xml = new XmlSlurper().parse(xmlString)

json.messageRequests.eachWithIndex { request, index ->
def previousName = xml.ProductMDMReplicateRequestMessage[index].Product.PreviousName.text()
request.body.extensions = ["ZExternalNumber": previousName]
}

def modifiedJson = JsonOutput.toJson(json)
message.setBody(modifiedJson)
return message
}


  1. Source payload is extracted from message header

  2. Value of element PreviousName is populated from source message into an extensions object with element name ZExternalNumber

  3. Since source can contain bulk messages, the enrichment is done inside an iterator

  4. JsonSlurper and XmlSlurper are used depending on the data format to parse the payloads

  5. The modified/enriched Json is sent to main integration flow which in turn is delivered to target system


Below is another example where source in JSON and target data format in XML, with the exception the sourcePayload is already a JSON object (parsing is not needed).
def Message quoteFollowUpExit(Message message) {
def sourcePayload = message.getHeaders().get("sourcePayload")

def body = message.getBody(java.io.Reader)
def xml = new XmlSlurper().parse(body)

// Extract the ZPurchaseOrderNumber from JSON
def zPurchaseOrderNumber = sourcePayload.messageRequests[0].body.extensions.ZPurchaseOrderNumber
def itemIdentifiers = sourcePayload.messageRequests[0].body.items.collect {
it.extensions.ZItemIdentifier
}

// Populate the extracted value into the XML. Replcace the content if the target element exists else add the element
if (xml.A_SalesOrderType.PurchaseOrderByCustomer)
xml.A_SalesOrderType.PurchaseOrderByCustomer.replaceBody(zPurchaseOrderNumber)
else
xml.A_SalesOrderType.appendNode {
PurchaseOrderByCustomer(zPurchaseOrderNumber)
}

xml.A_SalesOrderType.to_Item.A_SalesOrderItemType.each {
it ->
def itemIdentifier = itemIdentifiers.remove(0)
if (it.Material[0])
it.Material.replaceBody(itemIdentifier)
else
it.appendNode {
Material(itemIdentifier)
}
}
def resultXml = XmlUtil.serialize(xml)
message.setBody(resultXml)
return message;
}

In addition in extension integration flow other modelling steps can be used as needed to enrich the message. With this we come to conclusion of this blog, Happy Learning!!!
1 Comment