In Part 1, I explained the overall setup of B2B Advisory. How the TPM foundation was structured. With the Company, Trading Partner, and Systems configuration in place, the next critical layer is the Agreement.
In Part 2, I explained the setup of the agreement. How the agreemetn can help to identigy the business process along with the trading partner identifer how that works.
In this final part I will explain how the standard flow works and what customization I did to fullfill my requriement (integration with custom EDI XML).
Information about the standard EDI Integration package
Package name : Cloud Integration – Trading Partner Management V2 (can be found in discovery)
There are multiple option of the trigger available based on how the actual call trigger for example in this we have the iflow for AS2, AS2 MDN, IDoc, Process Direct and SOAP. All of them are exposed with endpoints which can be used as per the requirement.
Other then these iflow we have several other Iflows which are being used to process data as per the EDI File type along with to execute the business process defined in the agreements.
As my interface is the inbound interface where from one of the SFTP file needs to pick and IDoc ORDERS.ORDERS05. To complete this required I have create
flow 1 : which pick the file from the SFTP and parse/create the required headers which are essential for processing in further step.
the pasring steps is being handled by the 2nd flow Step 1b – write Message to Message Queue which I have modifed with customized XSLT and header, which support my configuration done while creating agreement (identifier for receiver).
The names of the headers I choose are not random, because in next IFlow where agreement identification are being executed, it picked these identifiers from the headers only to create agreement plain id. I have already mentioned the attributes of agreement plain ID and below are the headers list for the same.
OrderField in Match StringScript VariableHeader SourceCustomized1Adapter TypesndAdapterTypeSAP_COM_SND_Adapter_Typecustomized standard flow externlised parameter (headers)2Document StandardsndDocumentStandardSAP_EDI_Document_Standardcustomized standard flow externlised parameter (headers)3Message NamespacesndMessageNamespaceSAP_EDI_Message_Namespace 4Message VersionsndMessageVersionSAP_EDI_Message_Versioncustomized standard flow externlised parameter (headers)5Sender IDsndSenderIdSAP_EDI_Sender_IDcustomized standard flow externlised parameter (headers)6Sender ID QualifiersndSenderIdQualifierSAP_EDI_Sender_ID_Qualifiercustomized standard flow externlised parameter (headers)7Sender Partner TypesndSenderPartnerTypeSAP_EDI_Sender_Partner_Type 8Sender System IDsndSenderSystemIdSAP_EDI_GS_Sender_ID (later overwritten to “”) 9Sender System ID QualifiersndSenderSystemIdQualifierSAP_EDI_GS_Sender_ID_Qualifier 10Receiver IDsndReceiverIdSAP_EDI_Receiver_IDcustomized standard flow externlised parameter (headers)11Receiver ID QualifiersndReceiverIdQualifierSAP_EDI_Receiver_ID_Qualifiercustomized standard flow externlised parameter (headers)12Receiver Partner TypesndReceiverPartnerTypeSAP_EDI_Receiver_Partner_Type 13Receiver System IDsndReceiverSystemIdSAP_EDI_GS_Receiver_ID (later overwritten to “”) 14Receiver System ID QualifiersndReceiverSystemIdQualifierSAP_EDI_GS_Receiver_ID_Qualifier 15Message TypesndMessageTypeSAP_EDI_Message_Typecustomized standard flow externlised parameter (headers)
Groovy analysis : In case you have come accross the script “callPDwithHeaderParameters.groovy” you might seen the line where “PidStringTemplate” is being created with certain variables which are driven by the header mentioned above with some additional placeholder “%s” which further being replaced with “sndSenderId” and “sndReceiverId”.
// pidStrintTemplate
def PidStringTemplate = sndAdapterType + “-” + sndDocumentStandard + “-” + sndMessageNamespace + “-” + sndMessageVersion + “-%s-” + sndSenderIdQualifier + “-” + sndSenderPartnerType + “-” + sndSenderSystemId + “-” + sndSenderSystemIdQualifier + “-%s-” + sndReceiverIdQualifier + “-” + sndReceiverPartnerType + “-” + sndReceiverSystemId + “-” + sndReceiverSystemIdQualifier + “-” + sndMessageType;
// placing senderID and receiverID for placeholders %s
def defaultPid = String.format(PidStringTemplate, sndSenderId, sndReceiverId)
// creating parter ID plain string and md5 hash header
message.setHeader(“ACTUAL_PARTNER_ID”, partnerID);
message.setHeader(“SAP_Partner_ID_MATCH_String”, matchString);
message.setHeader(“SAP_TPM_ACTIVITYPARTNER_ID”, partnerID);
These are the complete steps which need to be performed for customized EDIFacts processing and what I did to achive my requriements.
Additional resource
Some times for partner based value mapping, we mainted the general data inside the transactions of an agreement, which can help during the dynamic field data mapping. to pick these values from agreement below code can be utilized. This code get the value from one of the header “ACTUAL_PARTNER_ID” which can be use to lookup inside the partnerDirectory data. All the general data we maintain under Activity paramters (agreement transaction) are stored under the “Binary parameter” with the ID “SAP_TPM_CustomActivityParams” in the form of JSon.
import com.sap.it.api.pd.PartnerDirectoryService;
import com.sap.it.api.ITApiFactory;
import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.json.*;
import com.sap.it.api.pd.BinaryData;
def Message processData(Message message) {
def pdService = ITApiFactory.getApi(PartnerDirectoryService.class, null)
if (pdService == null) throw new Exception(“Partner Directory Service not available”)
def partnerID = message.getHeaders().get(“ACTUAL_PARTNER_ID”);
if (partnerID != null) {
// dynamic parameters for custom activity
def customActivityParams = pdService.getParameter(“SAP_TPM_CustomActivityParams”, partnerID, BinaryData.class);
if (customActivityParams != null){
def customActivityParamsStr = new String(customActivityParams.getData());
def customActivityParamsJson = new JsonSlurper().parseText(customActivityParamsStr);
customActivityParamsJson.each{
paramKey, paramValue -> message.setProperty(paramKey, paramValue);
}
}
}
return message
}
Apart from these sometime complex value map can be maintained under Manager Partner Directory (under Manage Stores) which generally can be without partner specific but may be based on the Counrty, plant etc. This can be access with below code.
import com.sap.it.api.pd.PartnerDirectoryService
import com.sap.it.api.ITApiFactory
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// 1. Initialize Partner Directory Service
def pdService = ITApiFactory.getApi(PartnerDirectoryService.class, null)
if (pdService == null) throw new Exception(“Partner Directory Service not available”)
// 2. Handle First PID (Suffix logic)
// Assuming input PID comes from a header or property named ‘Input_PID’
String inputPid = message.getHeaders().get(“PD_APID”) ?: message.getProperties().get(“PD_APID”)
if (inputPid) {
String pid1 = inputPid + “_PD”
String val1 = pdService.getParameter(“SNDPRN”, pid1, String.class)
String val2 = pdService.getParameter(“SNDPRT”, pid1, String.class)
message.setProperty(“Partner_SNDPRN”, val1 ?: “”) // Empty if null
message.setProperty(“Partner_SNDPRT”, val2 ?: “”) // Empty if null
}
// 3. Handle Second PID (EDI_DC40_QA)
String pid2 = message.getHeaders().get(“SAP_ID”) ?: message.getProperties().get(“SAP_ID”)
// These can be changed based on the requirement and ID’s which maintained uder Partner Directory
def paramList = [“SNDPOR”, “RCVPOR”, “RCVPRT”, “RCVPRN”]
paramList.each { paramId ->
String value = pdService.getParameter(paramId, pid2, String.class)
// Store in property named ‘Partner_SNDPRT’, ‘Partner_SNDPOR’, etc.
message.setProperty(“Partner_” + paramId, value ?: “”)
}
return message
}
Thanks
Aman Sharma
In Part 1, I explained the overall setup of B2B Advisory. How the TPM foundation was structured. With the Company, Trading Partner, and Systems configuration in place, the next critical layer is the Agreement.In Part 2, I explained the setup of the agreement. How the agreemetn can help to identigy the business process along with the trading partner identifer how that works.In this final part I will explain how the standard flow works and what customization I did to fullfill my requriement (integration with custom EDI XML).Information about the standard EDI Integration packagePackage name : Cloud Integration – Trading Partner Management V2 (can be found in discovery)There are multiple option of the trigger available based on how the actual call trigger for example in this we have the iflow for AS2, AS2 MDN, IDoc, Process Direct and SOAP. All of them are exposed with endpoints which can be used as per the requirement. Other then these iflow we have several other Iflows which are being used to process data as per the EDI File type along with to execute the business process defined in the agreements.As my interface is the inbound interface where from one of the SFTP file needs to pick and IDoc ORDERS.ORDERS05. To complete this required I have createflow 1 : which pick the file from the SFTP and parse/create the required headers which are essential for processing in further step.the pasring steps is being handled by the 2nd flow Step 1b – write Message to Message Queue which I have modifed with customized XSLT and header, which support my configuration done while creating agreement (identifier for receiver).The names of the headers I choose are not random, because in next IFlow where agreement identification are being executed, it picked these identifiers from the headers only to create agreement plain id. I have already mentioned the attributes of agreement plain ID and below are the headers list for the same.OrderField in Match StringScript VariableHeader SourceCustomized1Adapter TypesndAdapterTypeSAP_COM_SND_Adapter_Typecustomized standard flow externlised parameter (headers)2Document StandardsndDocumentStandardSAP_EDI_Document_Standardcustomized standard flow externlised parameter (headers)3Message NamespacesndMessageNamespaceSAP_EDI_Message_Namespace 4Message VersionsndMessageVersionSAP_EDI_Message_Versioncustomized standard flow externlised parameter (headers)5Sender IDsndSenderIdSAP_EDI_Sender_IDcustomized standard flow externlised parameter (headers)6Sender ID QualifiersndSenderIdQualifierSAP_EDI_Sender_ID_Qualifiercustomized standard flow externlised parameter (headers)7Sender Partner TypesndSenderPartnerTypeSAP_EDI_Sender_Partner_Type 8Sender System IDsndSenderSystemIdSAP_EDI_GS_Sender_ID (later overwritten to “”) 9Sender System ID QualifiersndSenderSystemIdQualifierSAP_EDI_GS_Sender_ID_Qualifier 10Receiver IDsndReceiverIdSAP_EDI_Receiver_IDcustomized standard flow externlised parameter (headers)11Receiver ID QualifiersndReceiverIdQualifierSAP_EDI_Receiver_ID_Qualifiercustomized standard flow externlised parameter (headers)12Receiver Partner TypesndReceiverPartnerTypeSAP_EDI_Receiver_Partner_Type 13Receiver System IDsndReceiverSystemIdSAP_EDI_GS_Receiver_ID (later overwritten to “”) 14Receiver System ID QualifiersndReceiverSystemIdQualifierSAP_EDI_GS_Receiver_ID_Qualifier 15Message TypesndMessageTypeSAP_EDI_Message_Typecustomized standard flow externlised parameter (headers)Groovy analysis : In case you have come accross the script “callPDwithHeaderParameters.groovy” you might seen the line where “PidStringTemplate” is being created with certain variables which are driven by the header mentioned above with some additional placeholder “%s” which further being replaced with “sndSenderId” and “sndReceiverId”.// pidStrintTemplate
def PidStringTemplate = sndAdapterType + “-” + sndDocumentStandard + “-” + sndMessageNamespace + “-” + sndMessageVersion + “-%s-” + sndSenderIdQualifier + “-” + sndSenderPartnerType + “-” + sndSenderSystemId + “-” + sndSenderSystemIdQualifier + “-%s-” + sndReceiverIdQualifier + “-” + sndReceiverPartnerType + “-” + sndReceiverSystemId + “-” + sndReceiverSystemIdQualifier + “-” + sndMessageType;
// placing senderID and receiverID for placeholders %s
def defaultPid = String.format(PidStringTemplate, sndSenderId, sndReceiverId)
// creating parter ID plain string and md5 hash header
message.setHeader(“ACTUAL_PARTNER_ID”, partnerID);
message.setHeader(“SAP_Partner_ID_MATCH_String”, matchString);
message.setHeader(“SAP_TPM_ACTIVITYPARTNER_ID”, partnerID);These are the complete steps which need to be performed for customized EDIFacts processing and what I did to achive my requriements. Additional resourceSome times for partner based value mapping, we mainted the general data inside the transactions of an agreement, which can help during the dynamic field data mapping. to pick these values from agreement below code can be utilized. This code get the value from one of the header “ACTUAL_PARTNER_ID” which can be use to lookup inside the partnerDirectory data. All the general data we maintain under Activity paramters (agreement transaction) are stored under the “Binary parameter” with the ID “SAP_TPM_CustomActivityParams” in the form of JSon.import com.sap.it.api.pd.PartnerDirectoryService;
import com.sap.it.api.ITApiFactory;
import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.json.*;
import com.sap.it.api.pd.BinaryData;
def Message processData(Message message) {
def pdService = ITApiFactory.getApi(PartnerDirectoryService.class, null)
if (pdService == null) throw new Exception(“Partner Directory Service not available”)
def partnerID = message.getHeaders().get(“ACTUAL_PARTNER_ID”);
if (partnerID != null) {
// dynamic parameters for custom activity
def customActivityParams = pdService.getParameter(“SAP_TPM_CustomActivityParams”, partnerID, BinaryData.class);
if (customActivityParams != null){
def customActivityParamsStr = new String(customActivityParams.getData());
def customActivityParamsJson = new JsonSlurper().parseText(customActivityParamsStr);
customActivityParamsJson.each{
paramKey, paramValue -> message.setProperty(paramKey, paramValue);
}
}
}
return message
}Apart from these sometime complex value map can be maintained under Manager Partner Directory (under Manage Stores) which generally can be without partner specific but may be based on the Counrty, plant etc. This can be access with below code.import com.sap.it.api.pd.PartnerDirectoryService
import com.sap.it.api.ITApiFactory
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// 1. Initialize Partner Directory Service
def pdService = ITApiFactory.getApi(PartnerDirectoryService.class, null)
if (pdService == null) throw new Exception(“Partner Directory Service not available”)
// 2. Handle First PID (Suffix logic)
// Assuming input PID comes from a header or property named ‘Input_PID’
String inputPid = message.getHeaders().get(“PD_APID”) ?: message.getProperties().get(“PD_APID”)
if (inputPid) {
String pid1 = inputPid + “_PD”
String val1 = pdService.getParameter(“SNDPRN”, pid1, String.class)
String val2 = pdService.getParameter(“SNDPRT”, pid1, String.class)
message.setProperty(“Partner_SNDPRN”, val1 ?: “”) // Empty if null
message.setProperty(“Partner_SNDPRT”, val2 ?: “”) // Empty if null
}
// 3. Handle Second PID (EDI_DC40_QA)
String pid2 = message.getHeaders().get(“SAP_ID”) ?: message.getProperties().get(“SAP_ID”)
// These can be changed based on the requirement and ID’s which maintained uder Partner Directory
def paramList = [“SNDPOR”, “RCVPOR”, “RCVPRT”, “RCVPRN”]
paramList.each { paramId ->
String value = pdService.getParameter(paramId, pid2, String.class)
// Store in property named ‘Partner_SNDPRT’, ‘Partner_SNDPOR’, etc.
message.setProperty(“Partner_” + paramId, value ?: “”)
}
return message
} ThanksAman Sharma Read More Technology Blog Posts by Members articles
#SAP
#SAPTechnologyblog