3

SAP EDI/IDoc Communication in CPI Using Bundling and Fewer Mapping Artifacts

 2 years ago
source link: https://blogs.sap.com/2022/05/04/sap-edi-idoc-communication-using-bundling-and-fewer-mapping-artifacts/
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.
neoserver,ios ssh client
May 4, 2022 8 minute read

SAP EDI/IDoc Communication in CPI Using Bundling and Fewer Mapping Artifacts

0 0 102

Introduction

Not sure how many folks have reviewed the semi-recent announcement regarding Trading Partner Management in SAP Integration Suite Announcement: SAP Trading Partner Management and B2B Monitoring brand new capabilities of SAP Integration Suite is released! and were as disappointed as me with the initial product delivery.  I have two core issues with the approach:

  1. Still no support for bundling IDocs despite its longtime existence on the back-end and it’s noted SAP Help EDI Converter – that’s ok… I’ll tackle it on my own
  2. Bloated maintenance of mapping artifacts per partner – too many folks have missed the point on EDI communication and the proposed solution is no different.  Last I checked I’m still bound by the amount of time available in a day, and my company has at least a couple dozen EDI partners

Stay tuned for a part II that will address incoming communication for 997s and have the groundwork for other transaction sets

Prerequisites for Bulk and Determination of EDI Standard

The message function code is mapped to the appropriate field in the group segment while the package size handles the bundling, and in the other image the values are used to determine the appropriate X12 target without having to read from the TPM agreements.

Bulk

EDI%20Standard

Transformation Flow

The initial transformation flow is based off this older ICA template with some modifications to handle the splitting for bulk, and saving the IDoc numbers in a datastore for retrieval on incoming 997s.

Main%20Flow

Extract Basic Information and Write to Datastore

The first two steps gather some basic IDoc information, establish the sender partner id, and generate a interchange control number, followed by saving the IDoc #s in the datastore with the interchange control number as the entity id (Necessary for STATUS.SYSTAT01 communication later).  The following shows the established configuration for the write step to the datastore, and the XSL mapping step has not been included because it is your basic run of the mill XSL transform.

Write%20to%20Datastore

Partner Directory Script for Transformation

The third step taps into the partner directory via Groovy to read the header information for the necessary XSLT/XSD artifacts, but with one important distinction – the central mapping artifacts are tied to our partner directory entry with only extended post processing tied to the third party.

    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    import com.sap.it.api.pd.PartnerDirectoryService;
    import com.sap.it.api.ITApiFactory;

def Message processData(Message message) {

    def service = ITApiFactory.getApi(PartnerDirectoryService.class, null); 
    if (service == null){
      throw new IllegalStateException("Partner Directory Service not found");
    }
	
    // Read partner data for mapping functions and communication
    def headers = message.getHeaders();
    def SenderPid = headers.get("SenderPid");
    def mestyp = headers.get("SAP_IDoc_MESTYP");
    def idoctyp = headers.get("SAP_IDoc_IDOCTYP");
    def std = headers.get("SAP_IDoc_STD"); 
    def stdmes = headers.get("SAP_IDoc_STDMES");
    def stdvrs = headers.get("SAP_IDoc_STDVRS");
    def rcvprn = headers.get("SAP_IDoc_RCVPRN");
    def test = headers.get("SAP_IDoc_TEST");
    
    // Setup header variables from PD for mapping read (AT items)
    // only use extended pre and post for partner specific mapping contexts
    def preproc, mapping, postproc, rec_validation;
    preproc = mestyp + "." + idoctyp + "_preproc";
    if(std == "X") {
      mapping = mestyp + "." + idoctyp + "_to_ASC-X12_" + stdmes + "_" + stdvrs;
      postproc = "ASC-X12_" + stdmes + "_" + stdvrs + "_postproc";
      rec_validation = "ASC-X12_" + stdmes + "_" + stdvrs;
    }
    message.setHeader("PREPROC_XSLT", "pd:" + SenderPid + ":" + preproc + ":Binary");
    message.setHeader("MAPPING_XSLT", "pd:" + SenderPid + ":" + mapping + ":Binary");
    message.setHeader("POSTPROC_XSLT", "pd:" + SenderPid + ":" + postproc + ":Binary");
    // For syntax validation and/or edi to xml conversion at receiver side
    message.setHeader("REC_CONVERSION_XSD", "pd:" + SenderPid + ":" + rec_validation + ":Binary");
    
     // Retrieve our qualifier and id for ISA envelope and pass usage indicator
    def our_x12qual = service.getParameter("x12_qualifier", SenderPid, java.lang.String.class);
    message.setProperty("OurX12Qualifier", our_x12qual);
    def our_x12id = service.getParameter("x12_id", SenderPid, java.lang.String.class);
    message.setProperty("OurX12Id", our_x12id);
    message.setProperty("UsageIndicator", test == "X" ? "T" : "P");

    // Map alternative partner ID to partner id
    def ReceiverPid = service.getPartnerId("SAP SE", "IDOC", rcvprn);
    if (ReceiverPid == null){
      throw new IllegalStateException("Partner ID not found for agency SAP SE , scheme IDOC, and  id " + rcvprn);   
    }
    message.setHeader("ReceiverPid", ReceiverPid);
    
    // Retrieve partner specific information regarding interchange ids and 
    // other envelope settings, as well as extended post processing in appropriate
    // headers or properties
    def x12qual = service.getParameter("x12_qualifier", ReceiverPid, java.lang.String.class);
    message.setProperty("X12Qualifier", x12qual);
    def x12id = service.getParameter("x12_id", ReceiverPid, java.lang.String.class);
    message.setProperty("X12Id", x12id);
    def converter = service.getParameter("EDIConverter", ReceiverPid, java.lang.String.class);
    message.setProperty("converter", converter);
    def extendedPost = "ext_ASC-X12_" + stdmes + "_" + stdvrs + "_postproc";
    def doExtendedPost = service.getParameter("do_" + extendedPost, ReceiverPid, java.lang.String.class);
    if(doExtendedPost == "true") {
      message.setProperty("DoExtPostprocessing", doExtendedPost);
      message.setHeader("EXT_POSTPROC_XSLT", "pd:" + ReceiverPid + ":" + extendedPost + ":Binary");
    }
    
    return message;
}
Determine Envelope Type

The retrieval of the partner directory information is followed by the interchange mapping which has been configured as a local integration process with a general splitter and gather step sandwiching the necessary mapping steps.  It also includes one additional XSLT step not found in the older standard ICA content that manages the segment counter in the S_SE segment, and was referenced from Integration Advisor: Functions at target side – Ordinal number for line items and segment count.  Once the interchange mapping is complete the enveloped is constructed using the same mechanism as the older ICA template, but with the inclusion of a router based on version number.  The route for 004010 is the default with the expression for the other route as follows:

Envelope%20Router

Determine EDI Converter Type

The EDI converter that executes will also be recorded in the partner directory and a separate iFlow will need to be created for any converter variation for segment terminators, data element separators, composite data element separators, etc. (Not a fan that these are not available as headers for manipulation of processing!!).  Below is the setup of the routing and communication information as well as a sample of a non-standard flow we will probably need down the road because we have some customers that use the pipe character for the data element separator.

Converter%20Router

Converter%20Channel

Converter%20Non-standard

Transactional Control Numbers and Total Transaction Count

An extra XSL transform that is a variation of the segment counter XSL with some additional logic to output transactional control numbers based on position + 1.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>
    <!-- ============================================================================================= -->
    <!-- Template: Enter the count of segments -->
    <!-- ============================================================================================= -->
    <xsl:template match="D_97">
        <D_97>
            <xsl:value-of select="count(//*[name() = 'S_ST'])"/>
        </D_97>
    </xsl:template>
    <!-- ============================================================================================= -->
    <!-- Template: Determine Transaction Set Control Number -->
    <!-- ============================================================================================= -->
    <xsl:template match="D_329">
        <D_329><xsl:value-of select="format-number(count(../../preceding-sibling::*)+1, '000000000')"/></D_329>
    </xsl:template>
    <!-- ============================================================================================= -->
    <!-- Template: Consume and produce remaining nodes -->
    <!-- ============================================================================================= -->
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
The Last Step

The final step is simply there to remove some header information from the envelope step where the system complains about improper CRLF characters and set a header for pid which is used in the communication flow.

Communication Flow

The communication flow is setup with a JMS queue with simple retry every 15 minutes settings and an exception sub-process to handle email alerting periodically if a message is not going out.  For the most part this flow is WYSIWYG.  Maybe you would ask… why the partner directory lookup again, but that is simply for separating transformation logic from communication logic which will be obvious in the script code.  The SFTP code is still a work in progress because I do not have a use case yet, but have seen it in the past, and the IDoc work will be referenced in part II.

Communication%20Flow

Partner Directory Script for Communication

Gather adapter information and, if necessary, details related to third party communication for AS2 and SFTP usage.

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.pd.PartnerDirectoryService;
import com.sap.it.api.ITApiFactory;
def Message processData(Message message) {
    def service = ITApiFactory.getApi(PartnerDirectoryService.class, null); 
    if (service == null){
        throw new IllegalStateException("Partner Directory Service not found");
    }
    
    // Merge Partner Directory data into message header
    def headers = message.getHeaders();
    def pid = headers.get("pid");
    def adapter = service.getParameter("AdapterType", pid, java.lang.String.class);
    message.setProperty("adapter", adapter);
    if(adapter == "AS2") {
      def url = service.getParameter("ReceiverUrl", pid, java.lang.String.class);
      message.setProperty("Url", url);
      def recipientAS2 = service.getParameter("AS2_id", pid, java.lang.String.class);
      message.setProperty("RecipientAS2", recipientAS2);
      def publicKey = service.getParameter("PublicKeyAlias", pid, java.lang.String.class);
      message.setProperty("PublicKeyAlias", publicKey);
      def compress = service.getParameter("SAP_AS2_Outbound_Compress_Message", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Compress_Message", compress);
      def signMessage = service.getParameter("SAP_AS2_Outbound_Sign_Message", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Sign_Message", signMessage);
      def signAlgorithm = service.getParameter("SAP_AS2_Outbound_Signing_Algorithm", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Signing_Algorithm", signAlgorithm);
      def encryptMessage = service.getParameter("SAP_AS2_Outbound_Encrypt_Message", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Encrypt_Message", encryptMessage);
      def encryptAlgorithm = service.getParameter("SAP_AS2_Outbound_Encryption_Algorithm", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Encryption_Algorithm", encryptAlgorithm);
      def mdnType = service.getParameter("SAP_AS2_Outbound_Mdn_Type", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Type", mdnType);
      def mdnRequestSign = service.getParameter("SAP_AS2_Outbound_Mdn_Request_Signing", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Request_Signing", mdnRequestSign);
      def mdnSignAlgorithm = service.getParameter("SAP_AS2_Outbound_Mdn_Signing_Algorithm", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Signing_Algorithm", mdnSignAlgorithm);
      def mdnVerifySign = service.getParameter("SAP_AS2_Outbound_Mdn_Verify_Signature", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Verify_Signature", mdnVerifySign);
      def mdnRequestMic = service.getParameter("SAP_AS2_Outbound_Mdn_Request_Mic", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Request_Mic", mdnRequestMic);
      def mdnVerifyMic = service.getParameter("SAP_AS2_Outbound_Mdn_Verify_Mic", pid, java.lang.String.class);
      message.setHeader("SAP_AS2_Outbound_Mdn_Verify_Mic", mdnVerifyMic);
    } else if(adapter == "SFTP") {
      // TODO
    }

    return message;
}

Conclusion

Not a whole lot to say here, but rather to show it can be done.  The important note being that it is not supported so take it under advisement and do so at your own risk.  I encourage folks to comment, like, and ask any questions (Some detail was glossed over for brevity).  Cheers!

References

https://blogs.sap.com/2021/12/17/announcement-sap-trading-partner-management-and-b2b-monitoring-brand-new-capabilities-of-sap-integration-suite-is-released/

https://help.sap.com/docs/CLOUD_INTEGRATION/987273656c2f47d2aca4e0bfce26c594/707973f9bfb1419eb80628755494b962.html?q=edi%20converter

https://api.sap.com/integrationflow/IDOCToX12_4010_Outbound

https://blogs.sap.com/2020/12/10/integration-advisor-functions-at-target-payload-ordinal-number-for-line-items-and-segment-count/

https://blogs.sap.com/2016/08/11/hcihcp-isidoc-adapter-deciphered-part-4-trigger-idoc-from-hci-to-sap-erp-using-basic-authentication/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK