Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
I have experience of about 8 years in SAP PI/PO/CPI. Currently working as a CPI Developer.

Background

We have a requirement where we were asked to build a monitoring tool for a specific market. We built one html solution in CPI where we will accept the input from the end market users and display the messages that has passed for the Iflow and Date Range selected. We first built one user interface using html and java script and then made a post call with headers as parameters passed to the second Integration process, where we did the CPI Odata API’s call using the inputs from the first Integration Process. We then split the records and append the output in a html format and display it.

The key fields for the individual interfaces were stored in Custom Header using hashmap, which was suggested by my colleague Shwetha Devanand and she also helped in designing another solution via SAP Fiori, where the User Interface is being developed in Fiori and CPI fetches the data via Odata API and sends in Json format to Fiori application.

In the Integration Process 1, we display the User Interface and then make the post call to the other Integration Process.


Iflow with both the Integration Process



IntegrationProcess1


In the Integration Process 1, we have written the code for the display of Initial Home Page and the code is given below:

<!DOCTYPE html>
<html>
<head>
<p><img align="middle" src="ImageUrl.png?"
width="120" height="80">
<b style="font-size:25px;color:navy">Lighthouse: API Monitoring</b>
</p>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script>
function getInputValue(){
var inputVal = document.getElementById("mySelect").value;
var inputVal2 = document.getElementById("mySelect1").value;
let h = new Headers();
let url = 'your url to call the integration process';/* in our case we provided the Axway url and Axway was calling the second integration process.*/
h.append('iflowname',inputVal)  //value selected from interface dropdown list
h.append('daterange',inputVal2)//value selected from daterange dropdown list
fetch(url,{
method:'POST',
headers:h,
credentials:'include'

}).then(response => response.text())
.then(function (html) {

// Convert the HTML string into a document object
console.log(h);
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
document.getElementById("data").innerHTML += html;

}).catch(function (err) {
// There was an error
console.warn('Something went wrong.', err);
});
}
function refreshPage(){
document.getElementById("data").innerHTML = "";
}
</script>

</head>
<body style="background-color:powderblue;">
<form>
<b> Select Interface and Date Range from dropdown list </b>
<select id="mySelect" onchange="refreshPage()">
<option>MATMAS</option>
<option>DESADV</option>
<option>DeliveryNote</option>
<option>MBGMCR</option>
<option>WHSCON</option>
<option>ZINVRECI</option>
<option>SHPCON</option>
<option>WHSORD</option>
<option>SHPORD</option>
<option>ALL</option>
</select>
<select id="mySelect1" onchange="refreshPage()">
<option>Last24Hours</option>
<option>LastHour</option>
<option>LastWeek</option>
</select>
</form>
<button class="btn btn-dark" type="button" onclick="getInputValue();">Get Status</button>
<div id = "data"></div>
</body>
</html>

This will Display this page:


Initial Home Page


In this page we will select the interface and the date range from the drop down list.


InterfaceList



DateRange


 

Now we select the option and click on Get Status, which will call the other integration process with the values selected in the drop down list as Header(we can find that in the above code)

Now the second Integration process gets called from the Integration Process1 as given in the image below:


Integration Process


In the first step we build the query based on header received from IntegrationProcess1

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.text.SimpleDateFormat ;
import java.util.Date;
import groovy.time.TimeCategory
def Message processData(Message message) {
use(groovy.time.TimeCategory) {
def map = message.getHeaders();
def value = map.get("iflowname")
def daterange = map.get("daterange")
def time,query
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
def currentDate = new Date()

//Add increment hour by 1
if(daterange.equals("LastHour")){
def lastHour = currentDate - 60.minutes
time = sdf.format(lastHour)
}
if(daterange.equals("Last24Hours")){
def last24Hour = currentDate - 24.hour
time = sdf.format(last24Hour)
}
if(daterange.equals("LastWeek")){
def lastWeek = currentDate - 1.week
time = sdf.format(lastWeek)
}
if(daterange.equals("LastMonth")){
def lastMonth = currentDate - 1.months;
lastMonth = sdf.format(lastMonth)
time = sdf.format(lastMonth)
}

// We can do this in a Value Mapping table also by maintaining the values selected

if(value.equals("MATMAS"))
value = "CorrespondingIflowname"
if(value.equals("SHPORD"))
value = "CorrespondingIflowname"
else if(value.equals("DeliveryNote"))
value = "CorrespondingIflowname"
else if(value.equals("WHSORD"))
value = "CorrespondingIflowname"
else if(value.equals("MBGMCR"))
value = "CorrespondingIflowname"
else if(value.equals("SHPCON"))
value = "CorrespondingIflowname"
else if(value.equals("WHSCON"))
value = "CorrespondingIflowname"
else if(value.equals("ZINVRECI"))
value = "CorrespondingIflowname"
else if(value.equals("DESADV"))
value = "CorrespondingIflowname"

if(value.equals("ALL")) /* mention all the iflowname for the option ALL*/
query = "=IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"or IntegrationArtifact/Name eq"+"'"+"Iflowname"+"'"+"and LogEnd gt datetime"+"'"+time+"'"+"&"
else
query = "=IntegrationArtifact/Name eq"+"'"+value+"'"+"and LogEnd gt datetime"+"'"+time+"'"+"&"
message.setProperty("Query", query);

return message;
}
}

Give the address as shown below in the Odata Adapter:


CPI Odata API


In the CustomQuery set the query as shown in the image below, and also we put the query property we set in the script earlier.


OdataQuery


After the Odata response is received,we do the message mapping and map the fields we need for displaying the html output


MessageMapping


Next, we split the records into individual messages


SplitMessage


Next, we fetch the values we need to display and store it in property


SetProperty


Next, we append the property in a html body as shown below:


setHtmlBody


<tr>
<td><IntegrationFlowName>${property.IntegrationFlowName}</IntegrationFlowName></td>
<td><ReferenceFields>${property.ReferenceFields}</ReferenceFields></td>
<td><Plant>${property.Plant}</Plant></td>
<td><IdocNumber>${property.IdocNumber}</IdocNumber></td>
<td><MessageTimeStamp>${property.MessageTimeStamp}</MessageTimeStamp></td>
<td><FailureReason>${property.IntegrationStatus}</FailureReason></td>
<td style="color:red;"><FailureReason>${property.FailureReason}</FailureReason></td>
<td><LogEnd>${property.LogEnd}</LogEnd></td>
</tr>

Next, we gather the split messages as shown below:


Gather


Now, in the final step we build the final Html, code is given below:


HtmlHeadandBodyCode


<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CPI Support</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body style="background-color:powderblue;">
<table class="table table-bordered">
<thead class="thead-dark">
<tr>
<th scope="col">IntegrationFlowName</th>
<th scope="col">ReferenceFields</th>
<th scope="col">Plant</th>
<th scope="col">IdocNumber</th>
<th scope="col">MessageTimeStamp</th>
<th scope="col">IntegrationStatus</th>
<th scope="col">FailureReason</th>
<th scope="col">LogTime</th>
</tr>
</thead>
<tbody>
${in.body} // put the gathered body we got from the previous step
</tbody>
</body>
</html>

Next, when we select ALL, it displays the list of interfaces that have failed or ran successfully, similarly we can also view status of individual interfaces.


Output


Final Note

Try this in your interfaces as per your need. We can customize and use the CPI Odata API's for various other purposes.

That is it for this blog. Try this in your scenarios! Reward points if you like it!

References

https://blogs.sap.com/2019/03/25/sap-cloud-platform-integration-odata-api-for-accessing-the-service-...

https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/a617d6f37ddc43db8eeb1279662...

 
Labels in this area