Skip to Content

Scope:
Recently, I came across a specific requirement in SAP PI to implement,

  1. Pick a file from a server.
  2. Call two standard BAPI in a sequence in SAP ECC system.
  3. If first BAPI call fails, ignore it. But if second BAPI call fails, trigger a non-technical beautiful email to user along with payload as attachment.

Why not Alert Framework of SAP PI?
Using alert email, you can’t send exact BAPI failure to user. Alert framework generates a default error (below) along with too many technical details which can’t be understood by users.

I searched about the requirement on SCN, found this post,
https://scn.sap.com/thread/3743813

Proposed solution in the above thread, is implemented in ECC system, not in PI.
Here’s how I designed and implemented everything in PI without troubling our ABAPers.

Design:

 

Implementation:

ESR Objects:

Interfaces:
We will use following 4 interfaces, 1 outbound for receiving file in PI, 2 for BAPI calls and 1 for sending email to users.

File Outbound Interface (To receive file in SAP PI)
BAPI_1 (Import from SAP ECC system, for first BAPI call)
BAPI_2 (Import from SAP ECC system, for second BAPI call)
Mail Inbound Interface (To send email to Users)

Operation Mappings:
We will use 2 operation mappings. One for first BAPI call and one for Second BAPI call as RFC lookup and creating Email package.

1. File to BAPI_1 (Message Mapping: File to BAPI 1 Request)

2. File to BAPI_2 Response and Mail
(Message Mapping: File to BAPI 2 Request for creating BAPI request)
(Message Mapping: BAPI 2 Request to Response for RFC Look up)
(Message Mapping: BAPI 2 Response to Mail for creating Mail package)

a. File to BAPI 2 Request message mapping

b. BAPI 2 Request to Response message mapping

c. BAPI 2 Response to Mail message cum java mapping

I always prefer this approach for java mapping as you can test it right away like your graphical mapping.

Write Java Mapping directly in ESR!

Please find below Java code for parsing BAPI response and creating email package. You need to adjust it as per your requirement.

public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException
{
try{
//https://scn.sap.com/docs/DOC-64656
//Getting reference of output stream to write email package
      OutputStream os = out.getOutputPayload().getOutputStream();
      InputStream is =in.getInputPayload().getInputStream();
	  
//Dynamic configuration set up
DynamicConfigurationKey KEY_FILENAME =
       DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","FileName");

DynamicConfigurationKey KEY_FOLDER =
         DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","Directory");

DynamicConfigurationKey KEY_STAMP =
        DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","MTime");

DynamicConfiguration conf = in.getDynamicConfiguration();
String fname=conf.get(KEY_FILENAME);
String fdr=conf.get(KEY_FOLDER);
String stmp=conf.get(KEY_STAMP);

//Timestamp conversion from Unix format to simple format
SimpleDateFormat sdf = new SimpleDateFormat("MMMM d, yyyy 'at' h:mm a");
stmp= sdf.format(Long.parseLong(stmp) * 1000);

//CRLF
String CRLF = "\r\n";
String mailS,subj;
boolean err=false;  //BAPI Response flag
String fileName=in.getInputParameters().getString("PARAM_FILENAME");//import parameter,Simple Type,xsd:string

//Getting Email Addresses (Parametrized java Mapping)
		String fromEmail=  in.getInputParameters().getString("PARAM_FROM"); //import parameter,Simple Type,xsd:string, from email address
		String toEmail=in.getInputParameters().getString("PARAM_TO");//import parameter,Simple Type,xsd:string, to Email address
		String toEmailS=in.getInputParameters().getString("PARAM_TO_S");//import parameter,Simple Type,xsd:string, to Email address for successful case

//Adding trace                                      
		getTrace().addInfo("Copying input payload");
		
/*
Sample BAPI Response XML for the reference
	<RETURN>
		<item>
			<TYPE>E</TYPE> 
			<ID>00</ID> 
			<NUMBER>001</NUMBER> 
			<MESSAGE>Order: entry 00007 is already technically completed</MESSAGE> 
			<LOG_NO /> 
			<LOG_MSG_NO></LOG_MSG_NO> 
			<MESSAGE_V1></MESSAGE_V1> 
			<MESSAGE_V2></MESSAGE_V2> 
			<MESSAGE_V3></MESSAGE_V3> 
			<MESSAGE_V4 /> 
			<PARAMETER>PAR1</PARAMETER> 
			<ROW>0</ROW> 
			<FIELD /> 
			<SYSTEM>SAPPI</SYSTEM> 
		</item>
  </RETURN>

*/
//Initializing document builder for parsing BAPI response
         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
         Document doc = dBuilder.parse(in.getInputPayload().getInputStream());

String poi=doc.getElementsByTagName("NUMBER").item(0).getTextContent();		// Getting document number from "NUMBER" node in incoming xml

NodeList ret = doc.getElementsByTagName("RETURN");	//Extracting Return type from BAPI response under "RETURN" node
Element eret = (Element) ret.item(0);

NodeList itL=eret.getElementsByTagName("item");
String[] ty= new String[itL.getLength()];
String[] text= new String[itL.getLength()];
String[] par= new String[itL.getLength()];
//Looping item nodes in case of multiple rows, returned from BAPI
for (int i = 0; i < itL.getLength(); i++) {
Node itN=	itL.item(i);
Element eit = (Element) itN;
ty[i]=eit.getElementsByTagName("TYPE").item(0).getTextContent();   //Getting Response type "E", "I", "", "S"
if(ty[i].equals("E") || ty[i].equals("I"))
{
err=true;
text[i]=eit.getElementsByTagName("MESSAGE").item(0).getTextContent(); // Getting Reason of failure
par[i]=eit.getElementsByTagName("PARAMETER").item(0).getTextContent();// Parameter due to which BAPI call failed
}
}
if(err)
{
//Setting Mail subject, address, content in case of failure response
subj="interface FAILURE notification";
mailS="Interface triggered has failed for document number"+CRLF
+CRLF+"Number:        "+poi+CRLF
+CRLF+"Error Message: ";
for (int j = 0; j < itL.getLength(); j++) 
{
if(ty[j].equals("E") || ty[j].equals("I"))
{
mailS=mailS+CRLF+text[j]+CRLF;
                      //  +"Due to Parameter: "+par[j]+CRLF;
}
}
mailS=mailS+CRLF
+"Refer to attachment for more details"+CRLF+CRLF
+"File ID:           "+fname+CRLF
+"Directory:       "+"testdirectory/Outbound"+CRLF
+"Time Stamp: "+stmp+CRLF+CRLF+CRLF+CRLF
+"Please investigate and contact to reprocess failed message if required.";
}
else
{
//Setting Mail subject, address, content in case of successful response
subj="interface SUCCESS notification";
mailS="Interface triggered has processed successfully for document number"+CRLF
+CRLF+"Number:        "+poi+CRLF+CRLF
+"Refer to attachment for more details"+CRLF+CRLF
+"File ID:           "+fname+CRLF
+"Directory:       "+"testdirectory/Outbound"+CRLF
+"Time Stamp: "+stmp;
}

ByteArrayOutputStream baos = new ByteArrayOutputStream();//ByteArrayOutputStream to write incoming BAPI response as attachment
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
    baos.write(buffer, 0, length);
}
//Creating Attachment
getTrace().addInfo("Attachment created");
if(!err)
toEmail=toEmailS;

String boundary="--AaZz";
String emailPackage= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
        + "<ns:Mail xmlns:ns=\"http://sap.com/xi/XI/Mail/30\">"
        + "<Subject>" +subj+"</Subject>"
        + "<From>" + fromEmail + "</From>"
        + "<To>" + toEmail + "</To>"
        + "<Content_Type>multipart/mixed; boundary=\""
        + boundary
        + "\"</Content_Type>"
        + "<Content>";
     os.write(emailPackage.getBytes());//Writing Email Package in output stream 
// create the declaration of the MIME parts
      //First part
      emailPackage = "--" + boundary + CRLF
                + "Content-Type: text/plain; charset=UTF-8" + CRLF
                + "Content-Disposition: inline" + CRLF + CRLF
                + mailS + CRLF + CRLF                 

//Second part
                + "--" + boundary + CRLF
                + "Content-Type: application/xml; name=" + fileName + CRLF
                + "Content-Disposition: attachment; filename=" + fileName + CRLF + CRLF;
      os.write(emailPackage.getBytes());
      String sbuf = baos.toString("UTF-8");
    // replace all control characters with escape sequences
    sbuf = sbuf.replaceAll("&", "&amp;");
    sbuf = sbuf.replaceAll("\"", "&quot;");
    sbuf = sbuf.replaceAll("'", "&apos;");
    sbuf = sbuf.replaceAll("<", "&lt;");
    sbuf = sbuf.replaceAll(">", "&gt;");
	os.write(sbuf.getBytes("UTF-8"));
     emailPackage = CRLF + CRLF +"--" + boundary + "--" + CRLF;
      os.write(emailPackage.getBytes());
      // finish mail package
      os.write("</Content></ns:Mail>".getBytes());

     os.flush();                       //Flushing output stream
     os.close();     				   //Closing output stream

}
catch (Exception e)
   {
          throw new StreamTransformationException(e.getMessage());
   }  
}

You need to check ASMA (Adapter specific message attributes) in your sender file channel and define adapter type import parameter in order to get file name, directory during mapping execution.

Integration Directory Configuration:

Design an ICO in ID,

Inbound processing: Select your outbound interface, sender file channel.
Receiver: Select appropriate receiver of your configuration.
Receiver interface: Call Operation mapping in sequence if required. Configure parameter as per your mapping, for RFC lookup channel, email addresses, attachment name.

Outbound processing: for first BAPI call.

Outbound processing: for Email interface, BAPI call happens in mapping lookup.

Channel configurations:

Email: “Use Email package” should be checked and content encoding should be “none”.

 

RFC: You have to add Successful RETURN TYPE as E, I, S in advanced mode accordingly, so that you can capture both successful and failure responses during lookup.


Test:
Sample email generated from above setup.

Credits and references:

I referred following blog of Stefan Grube for Email package creation and mail adapter settings.

https://blogs.sap.com/2007/04/17/xi-mail-adapter-an-approach-for-sending-emails-with-attachment-with-help-of-java-mapping/

I also referred few other blogs for writing java code.

https://blogs.sap.com/2014/04/02/file-content-conversion-in-esr-using-java-mapping/

https://blogs.sap.com/2015/06/16/creating-multiple-files-zipping-sending-as-email-attachments-using-java-mapping/

Please leave your doubts and feedback in the comment section. I will try to clarify them as soon as I see them.

Regards,
Ambuj

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

  1. sai nikhil

    Hi ambuj mishra,

    Great Blog.

    1.Can u share the BAPI1,BAPI2,Mail Structures used in this scenario.

    2.What are the mail settings done by basis team for triggering a mail using mail receiver adapter we are using Single Stack SAP PO.

    3.You are passing single value to BAPI and can i pass multiple values to BAPI one csv file with multiple production orders.

     

    (0) 

Leave a Reply