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: 
jo_kr
Explorer
6,767

Introduction


Often you have the requirement to create a set of IDoc interfaces as a kind of template implementation, especially for EDI communication scenarios.

Regarding the EDI use case, you might have created a single iFlow receiving the partner's data and separate the incoming messages over operations.

For the other direction you realize the IDoc sender adapter requires a dedicated IDoc outbound interface with only one operation. So we cannot provide a single template interface with multiple operations for sending data to the partner, which is resolved here SAP PI B2B Add-on 3.0 – Outbound by using EDI separator.

My workaround is inspired by the blog post "Michal’s PO tips: How to send messages directly to AEX (ICO) – adapter independent – SOAPUI version... to implement the BAdI IDOC_XML_ENVELOPE_OU in order to wrap the XML IDoc into the SOAP envelope and adding the XI headers.

If you are also searching for a solution to either...

  1. provide generic IDoc outbound interfaces

  2. create acknowledgements per partner profile and not per Idoc sender channel (additional adapter module required for ALEAUDs)

  3. setup a simple solution to create the serialization context for IDocs (based on Xpath)
    -> Configuration instead of function module development

  4. have a generic and single HTTP endpoint for XML-HTTP IDoc ports instead of creating multiples (one endpoint for each SAP PO outbound interface)

  5. avoid header mappings for outbound interfaces in order to set the XI Party (KB: 1941832 - Resolve logical receiver party) or replace the virtual receiver Logical System (KB: 2728276 - Resolve logical receiver service for LS receiver)

  6. send the IDoc to a dedicated iFlow having a virtual receiver, which could e.g. represent a dedicated SAP process. This helps to separate IDoc iFlows into business responsibilities and you could create IDoc iFlows without any dependency to any other IDoc interface.
    (I know, it increases the amount of point2point interfaces, but if you ask business, I'm not sure they are interested in using as many integration patterns as possible 🙂
    -> Less discussion about impact and regression testing after changing existing interfaces

  7. use HTTP based communication instead of TRFC / ressource adapter configuration for sending IDocs, but still want the full/better SAP PO functionality (see restrictions) compared to the restricted default XML-HTTP port behavior
    or

  8. overcome the 16 character serialization context length


...this BAdI implementation and some little customizing might help you to achieve it with only a single iFlow.

BTW: No metadata is required anymore if you send it over HTTP-XML...

Please bear with me in case you find issues regarding the ABAP part,I’m still on beginner level.
I'm happy receive your ideas/use cases and feel free to provide any optimization proposals.

Warning: This BAdI is not yet used in production. So adjust it to your needs and test it carefully before using it in productive environments - No warranty for correctness, performance and no support can be provided! This is no SAP code. So it is 100% in your responsibility to troubleshoot and correct it in case of any issue.



Restrictions



  • You will not successfully receive back ALEAUDs without an additional adapter module.
    ALEAUDs will stuck in SAP PO, not finding the corresponding inbound IDoc.
    I’m checking if I can publish the module.

  • Your WE21 port name must match *PO[X]_* regex: ^.*PO.{0,1}_.*$ according to the code below.


Steps to implement the BAdI


Prerequisites


You should have at least basic ABAP development knowledge and create a package or know which development package needs to be selected before you continue with the next steps.

You must have at least 7.40 SAP Basis release to use the BAdI code below.

1. SAP PO SOAP sender channel (in SAP PO)


Make sure there is an active SOAP sender channel created for the Business System in where you implement the BAdI and this channel is used in ANY deployed iFlow/ICO, like shown in the referenced blog from michal.krawczyk2 entry from above.

2. Create RFC Destination (SM59)


Type: G
Host: your SAP PO system (without protocol, like http[s]://)
Service Your SAP PO Http Port
Path Prefix: /XISOAPAdapter/MessageServlet?channel=:<SenderComponentName>:<ChannelName>
Setup Authentication

e.g. /XISOAPAdapter/MessageServlet?channel=:ER6_800:CC_SND_SOAP

Please note the colons which separate Party (empty in our case) from the sender system (business system)




3. Create HTTP Idoc Port (WE21)


Name: SAP_PO_XI and assign it in the partner profile (copy/write the value manually if you do not find it with F4 help)



4. Create domains (SE11)


(Select domain, enter name and click create button for all 2)

Name: ZSSTRING
Description: <something you like>

Data Type: SSTRING
No. Characters: 1133
Lower Case: X


 

Name: ZRCVPRN
Description: <something you like>

Data Type: CHAR
No. Characters: 60
Lower Case: X


 

-> Save and activate both new domains

 

5. Create data elements (SE11)


(Select datatype, enter name and click create button, choose data element for all 2)

Name: ZXPATH
Description: <something you like>

Domain: ZSSTRING

Field Label Tab
Short: 10 <something you like>


 

Name: ZRCVPRN
Description: <something you like>

Domain: ZRCVPRN

Field Label Tab
Short: 10 <something you like>


 

-> Save and activate all 2 new data types

 

6. Create tables (SE11)


(Select database table, enter name and click create button for all 2)

Name: ZIDOCENVELOPEOUT

Delivery and Maintenance Tab

Delivery Class: C
Data Browser/Table Maintenance: Display Maintenance Allowed

Fields Tab

















































Field Data Element Key
.INCLUDE EDK13 X
IDOCTP EDIPIDOCTP
CIMTYP EDIPCIMTYP
QIDXPATH ZXPATH
CUSTSENDIF PRX_INTFID
CUSTSENDNS PRX_NSPCE
ERRORACK SAP_BOOL
SYSTEMACK SAP_BOOL



-> Technical settings

Data Class: APPL0
Size Category: 0

Regarding Buffering I am not sure, I’ve chosen “Not Allowed”

Log data changes X (Check with Basis for profile parameter rec/client <client> to make use of it)+

-> Extras -> Enhancement category -> can be enhanced

 

Name: ZIDOCENVELOUTNRO


Delivery and Maintenance Tab

Delivery Class: A
Data Browser/Table Maintenance: Display Maintenance Allowed with Restrictions

Fields Tab






















































Field Data Element Key
.INCLUDE EDK13 X
IDOCTP EDIPDOCTYP X
CIMTYP EDIPCIMTYP X
QUEUEID CHAR16 X
ZRCVPRN ZRCVPRN X
CHANGEDATE AS4DATE
CHANGETIME AS4TIME
XPATHRESULT ZXPATH
QIDXPATH_V ZXPATH



-> Technical settings

Data Class: APPL1
Size Category: 2

Regarding Buffering I am not sure, I’ve chosen “Not Allowed”

Log data changes [ ] No maintenance required -> no logging.

-> Extras -> Enhancement category -> can be enhanced

 

-> Save and activate both new database tables | ignore warnings about key length

 

7. Create number range object (SNRO)


(Select datatype, enter name and click create button, choose data element)

Name: ZQUEUEID

ShortTxt: <something you like>

Number length domain: char16
Buffering: No (if you don't like gaps)

Interval name: Z1
From: 0000000000000001
To:     9999999999999999



8. Create the BAdI class (SE18)


(Select BAdI Name, enter IDOC_XML_ENVELOPE_OU and click display button)

Transaction-Code:  SE18
BAdI Name: IDOC_XML_ENVELOPE_OU

 

-> Implementation -> Create


Name: ZIDOC_XML_ENVELOPE_O

(enter name and click OK (green arrow) button)

Tab Interface


Double-click on PROCESS


(Click on Source code Based)


Copy and insert the code
Save and activate it.
CLASS zcl_im_idoc_xml_envelope_o DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

INTERFACES if_ex_idoc_xml_envelope_ou .

PROTECTED SECTION.
PRIVATE SECTION.

CONSTANTS gc_idoc_xml_envelope_ou_name TYPE string VALUE 'ZCLIMIDOCXMLENV_O' ##NO_TEXT.
CONSTANTS gc_idoc_xml_envelope_ou_rcvpor TYPE string VALUE '^.*PO.{0,1}_.*$' ##NO_TEXT.
CONSTANTS gc_idoc_xml_zidocenvelpout_v TYPE string VALUE 'ZIDOCENVELOPEOUT' ##NO_TEXT.
CONSTANTS gc_direct_outbound TYPE string VALUE '1' ##NO_TEXT.

METHODS create_message
IMPORTING
!iv_msgno TYPE edi_stamno
!iv_msgv1 TYPE any OPTIONAL
!iv_msgv2 TYPE any OPTIONAL
!iv_msgv3 TYPE any OPTIONAL
!iv_msgv4 TYPE any OPTIONAL
RETURNING
VALUE(rs_message) TYPE idocstatmp .
METHODS evaluate_xpath
IMPORTING
!idoc_string TYPE string
!xpath TYPE zxpath
RETURNING
VALUE(result) TYPE string .
METHODS getqueueid
IMPORTING
!control TYPE edidc
!xpath TYPE zxpath
!xpathresult TYPE zxpath
!zrcvprn TYPE zrcvprn
RETURNING
VALUE(queueid) TYPE char16 .
METHODS findenveloperecord
IMPORTING
!control TYPE edidc
!xpath TYPE zxpath
!xpathresult TYPE zxpath
!zrcvprn TYPE zrcvprn
RETURNING
VALUE(env_record) TYPE zidocenveloutnro .
ENDCLASS.



CLASS ZCL_IM_IDOC_XML_ENVELOPE_O IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_IM_IDOC_XML_ENVELOPE_O->CREATE_MESSAGE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_MSGNO TYPE EDI_STAMNO
* | [--->] IV_MSGV1 TYPE ANY(optional)
* | [--->] IV_MSGV2 TYPE ANY(optional)
* | [--->] IV_MSGV3 TYPE ANY(optional)
* | [--->] IV_MSGV4 TYPE ANY(optional)
* | [<-()] RS_MESSAGE TYPE IDOCSTATMP
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD create_message.

* Check for consistency
IF iv_msgno IS INITIAL.
RAISE EXCEPTION TYPE cx_fatal_exception.
ENDIF.

CLEAR rs_message.

* Fill message structure
rs_message-stamid = gc_idoc_xml_envelope_ou_name.
rs_message-stamno = iv_msgno.
IF iv_msgv1 IS SUPPLIED.
rs_message-stapa1 = iv_msgv1.
ENDIF.
IF iv_msgv2 IS SUPPLIED.
rs_message-stapa2 = iv_msgv2.
ENDIF.
IF iv_msgv3 IS SUPPLIED.
rs_message-stapa3 = iv_msgv3.
ENDIF.
IF iv_msgv4 IS SUPPLIED.
rs_message-stapa4 = iv_msgv4.
ENDIF.
rs_message-repid = sy-repid.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_IM_IDOC_XML_ENVELOPE_O->EVALUATE_XPATH
* +-------------------------------------------------------------------------------------------------+
* | [--->] IDOC_STRING TYPE STRING
* | [--->] XPATH TYPE ZXPATH
* | [<-()] RESULT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD evaluate_xpath.

DATA: separator(1) TYPE c VALUE '&',
full TYPE abap_bool.

* DESCRIBE FIELD result LENGTH DATA(clen) IN CHARACTER MODE. " no neeed to loop more than max length

DATA(xpp) = NEW cl_proxy_xpath( ).
xpp->set_source_string( idoc_string ).
xpp->run( expression = xpath ).
DATA(nodes) = xpp->get_nodes( ).
IF NOT nodes IS INITIAL.
DATA(node) = nodes->get_next( ).
WHILE node IS BOUND AND NOT node IS INITIAL AND NOT full = abap_true.
DATA(s) = node->get_value( ).
DATA(typ) = node->get_type( ).
CONCATENATE result s INTO result SEPARATED BY separator .
node = nodes->get_next( ).
ENDWHILE.
REPLACE REGEX '^' && separator && '+|' && separator && '+$' IN result WITH ''. " remove pipe at the end if there is one
ENDIF.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_IM_IDOC_XML_ENVELOPE_O->FINDENVELOPERECORD
* +-------------------------------------------------------------------------------------------------+
* | [--->] CONTROL TYPE EDIDC
* | [--->] XPATH TYPE ZXPATH
* | [--->] XPATHRESULT TYPE ZXPATH
* | [--->] ZRCVPRN TYPE ZRCVPRN
* | [<-()] ENV_RECORD TYPE ZIDOCENVELOUTNRO
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD findenveloperecord.
SELECT * FROM zidocenveloutnro
WHERE rcvprt = @control-rcvprt
AND rcvprn = @control-rcvprn
AND rcvpfc = @control-rcvpfc
AND mestyp = @control-mestyp
AND mescod = @control-mescod
AND mesfct = @control-mesfct
AND test = @control-test
AND idoctp = @control-idoctp
AND cimtyp = @control-cimtyp
AND xpathresult = @xpathresult
AND zrcvprn = @zrcvprn
AND qidxpath_v = @xpath
INTO @env_record.
ENDSELECT.
ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_IM_IDOC_XML_ENVELOPE_O->GETQUEUEID
* +-------------------------------------------------------------------------------------------------+
* | [--->] CONTROL TYPE EDIDC
* | [--->] XPATH TYPE ZXPATH
* | [--->] XPATHRESULT TYPE ZXPATH
* | [--->] ZRCVPRN TYPE ZRCVPRN
* | [<-()] QUEUEID TYPE CHAR16
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD getqueueid.
DATA: enqueued TYPE abap_bool,
wa_record TYPE zidocenveloutnro,
rc TYPE inri-returncode,
loops TYPE n VALUE 1,
maxloops TYPE i VALUE 10.

TRY.
* Query to get the unique (single) record if same was already processed.
wa_record = me->findenveloperecord( control = control xpath = xpath xpathresult = xpathresult zrcvprn = zrcvprn ).

WHILE NOT enqueued EQ abap_true AND loops < maxloops AND wa_record IS INITIAL. " enqueue table for insert

loops = loops + 1. " avoid endless loop

* Enqueue for insert, if new
CALL FUNCTION 'ENQUEUE_E_TABLE'
EXPORTING
mode_rstable = 'E'
_wait = 'X'
tabname = 'ZIDOCENVELOUTNRO'.
IF sy-subrc = 0.
enqueued = abap_true.
ELSE.
IF loops >= maxloops .
RAISE EXCEPTION TYPE cx_abap_pragma_enqueue.
ENDIF.
WAIT UP TO 2 SECONDS.
ENDIF.

* Check again to make sure no insert happened during wait for enqueue
wa_record = me->findenveloperecord( control = control xpath = xpath xpathresult = xpathresult zrcvprn = zrcvprn ).

IF enqueued EQ abap_true AND wa_record IS INITIAL.
" should only be reached if enqued
IF xpathresult IS NOT INITIAL. " only if serialization is required
CALL FUNCTION 'NUMBER_GET_NEXT'
EXPORTING
nr_range_nr = 'Z1'
object = 'ZQUEUEID'
IMPORTING
number = queueid
returncode = rc.
IF sy-subrc <> 0 OR rc <> 0.
RAISE EXCEPTION TYPE cx_abap_load_error.
ENDIF.
ENDIF.

wa_record = VALUE #( BASE CORRESPONDING #( control ) qidxpath_v = xpath xpathresult = xpathresult changedate = sy-datum changetime = sy-uzeit queueid = queueid zrcvprn = zrcvprn ).

INSERT INTO zidocenveloutnro VALUES wa_record.
COMMIT WORK.

ENDIF.
*end of enque, if new
ENDWHILE.

* return queueid (also empty/initial ones) if successfully retrieved otherwise exception
IF wa_record IS NOT INITIAL.
queueid = wa_record-queueid.
ELSE.
RAISE EXCEPTION TYPE cx_abap_load_error.
ENDIF.

CATCH cx_root.
RAISE EXCEPTION TYPE cx_abap_load_error.

CLEANUP.
IF enqueued EQ abap_true.
CALL FUNCTION 'DEQUEUE_E_TABLE'
EXPORTING
mode_rstable = 'E'
tabname = 'ZIDOCENVELOUTNRO'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_load_error.
ENDIF.
ENDIF.

ENDTRY.

ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_IM_IDOC_XML_ENVELOPE_O->IF_EX_IDOC_XML_ENVELOPE_OU~PROCESS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IDOC_XML TYPE XSTRING
* | [--->] CONTROL TYPE EDIDC
* | [<---] OUTBOUND_XML TYPE XSTRING
* | [<---] ERROR TYPE CHAR1
* | [<---] PROTOCOL TYPE IDOCSTATMP
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD if_ex_idoc_xml_envelope_ou~process.

TYPE-POOLS: ixml.

DATA: lo_stream_factory TYPE REF TO if_ixml_stream_factory,
lo_input_stream TYPE REF TO if_ixml_istream,
lo_output_stream TYPE REF TO if_ixml_ostream,
lo_document TYPE REF TO if_ixml_document,
lo_parser TYPE REF TO if_ixml_parser,
lo_parse_error TYPE REF TO if_ixml_parse_error,
lo_renderer TYPE REF TO if_ixml_renderer,
lo_ixml TYPE REF TO if_ixml.

DATA:
lv_idocout_s TYPE string,
errorcount TYPE integer VALUE 0.

* Reset exporting parameters
CLEAR outbound_xml.
CLEAR error.
CLEAR protocol.

*+-------------------------------------------------------------------------------------------------+
* Do initial checks and return if they are not fullfilled with original payload
*+-------------------------------------------------------------------------------------------------+
outbound_xml = idoc_xml.

IF idoc_xml IS INITIAL.
RETURN. " Exit anyway
ENDIF.
* Check the port to be relevant
DATA: portmatch TYPE match_result.

FIND FIRST OCCURRENCE OF REGEX gc_idoc_xml_envelope_ou_rcvpor IN control-rcvpor RESULTS portmatch.
IF portmatch IS INITIAL. " IDOC receiver port is not a *PO[x]_ destiantion
RETURN.
ENDIF.

IF control-direct <> gc_direct_outbound. " Direction is not "1 - Outbound"
RETURN.
ENDIF.

TRY.
* +-------------------------------------------------------------------------------------------------+
* | Convert xstring to string, default UTF-8 encoding
* +-------------------------------------------------------------------------------------------------+
DATA(idoc_string) = cl_abap_codepage=>convert_from( source = idoc_xml ).

* +-------------------------------------------------------------------------------------------------+
* | Save for later and now remove XML declaration from incoming XML
* +-------------------------------------------------------------------------------------------------+
DATA: matches TYPE match_result,
xml_declaration TYPE string.

FIND FIRST OCCURRENCE OF REGEX '<\?xml.*\?>' IN idoc_string RESULTS matches.
xml_declaration = idoc_string+matches-offset(matches-length).

REPLACE REGEX '<\?xml.*\?>' IN idoc_string WITH ''.

* +-------------------------------------------------------------------------------------------------+
* | Retrieve UUID as sysuuid_x
* +-------------------------------------------------------------------------------------------------+
DATA: uuid TYPE sysuuid_x.

CALL FUNCTION 'SYSTEM_UUID_CREATE'
IMPORTING
uuid = uuid.

* +-------------------------------------------------------------------------------------------------+
* | Format Message ID with hyphens as string
* +-------------------------------------------------------------------------------------------------+
DATA(msgid) = cl_soap_wsrmb_helper=>convert_uuid_raw_to_hyphened( uuid ).

* +-------------------------------------------------------------------------------------------------+
* | Get UTC timestamp
* +-------------------------------------------------------------------------------------------------+
DATA: lv_utc TYPE timestamp.

cl_abap_tstmp=>systemtstmp_syst2utc(
EXPORTING
syst_date = sy-datum
syst_time = sy-uzeit
IMPORTING
utc_tstmp = lv_utc ).

errorcount = errorcount + sy-subrc.

* +-------------------------------------------------------------------------------------------------+
* | Convert UTC timestamp into ISO format as string
* +-------------------------------------------------------------------------------------------------+
DATA: ts TYPE string.

ts = cl_xlf_date_time=>create( timestamp = lv_utc ).

* +-------------------------------------------------------------------------------------------------+
* | Retrieve business system name from SLD for sender service
* +-------------------------------------------------------------------------------------------------+
DATA: bs_name TYPE text60,
bs_capt TYPE string,
bs_role TYPE lcr_bs_role.

CALL FUNCTION 'LCR_GET_OWN_BUSINESS_SYSTEM'
EXPORTING
bypassing_cache = ' '
read_from_cache = ' '
update_cache_entry_timestamp = ' '
IMPORTING
bs_key_name = bs_name
bs_caption = bs_capt
bs_role = bs_role.

errorcount = errorcount + sy-subrc.

* +-------------------------------------------------------------------------------------------------+
* | Get data from the customizing table
* +-------------------------------------------------------------------------------------------------+
SELECT SINGLE * FROM zidocenvelopeout
WHERE rcvprt = @control-rcvprt
AND rcvprn = @control-rcvprn
AND rcvpfc = @control-rcvpfc
AND mestyp = @control-mestyp
AND mescod = @control-mescod
AND mesfct = @control-mesfct
AND idoctp = @control-idoctp
AND cimtyp = @control-cimtyp INTO @DATA(custv).

* +-------------------------------------------------------------------------------------------------+
* | Do the mapping of RCVPRN, which might be required for party due to SAP PO not accepting numbers
* +-------------------------------------------------------------------------------------------------+

DATA: rcvprn TYPE zrcvprn.

IF custv-zrcvprn IS NOT INITIAL.
rcvprn = custv-zrcvprn.
ELSE.
rcvprn = control-rcvprn.
ENDIF.

* +-------------------------------------------------------------------------------------------------+
* | Run the Xpath evaluation which is required to set serialization context (QueueId) in SAP PO
* +-------------------------------------------------------------------------------------------------+
DATA: xpathresult TYPE zxpath .

IF custv-qidxpath IS NOT INITIAL.
IF custv-qidxpath(1) = ''''.
xpathresult = custv-qidxpath.
REPLACE ALL OCCURRENCES OF '''' IN xpathresult WITH ''.
ELSE.
xpathresult = me->evaluate_xpath( idoc_string = idoc_string xpath = custv-qidxpath ).
ENDIF.
IF xpathresult IS INITIAL.
protocol = create_message(
iv_msgno = '006'
iv_msgv1 = 'Xpath found no value'
iv_msgv2 = 'Badi: ZCL_IM_IDOC_XML_ENVELOPE_O').
error = abap_true.
RETURN.
ENDIF.
ENDIF.

* +-------------------------------------------------------------------------------------------------+
* | Data preparation steps
* +-------------------------------------------------------------------------------------------------+
DATA: systemack TYPE string,
errorack TYPE string,
defaultif TYPE string,
queueid TYPE char16.

defaultif = control-mestyp && '.' && control-idoctp && '.' && control-cimtyp. "In case no custom Idoc interface required
REPLACE REGEX '\.$' IN defaultif WITH '' . " remove dot at the end in case no cimtype

IF custv-systemack = abap_false. " convert to xsd:boolean
systemack = 'false'.
ELSE.
systemack = 'true'.
ENDIF.

IF custv-errorack = abap_false.
errorack = 'false'.
ELSE.
errorack = 'true'.
ENDIF.
" will also be called in case no queuueid is required for join of view ZIDOCENVELPOUT_V
queueid = me->getqueueid( control = control xpath = custv-qidxpath xpathresult = xpathresult zrcvprn = custv-zrcvprn ).

* +-------------------------------------------------------------------------------------------------+
* | Add SAP PO SOAP envelope around xml to fill xi protocol parameters dnyamically
* +-------------------------------------------------------------------------------------------------+
CONCATENATE xml_declaration
'<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">'
'<SOAP:Header>'
'<sap:Main xmlns:sap="http://sap.com/xi/XI/Message/30" versionMajor="3" versionMinor="1" SOAP:mustUnderstand="1">'
'<sap:MessageClass>ApplicationMessage</sap:MessageClass>'
'<sap:ProcessingMode>asynchronous</sap:ProcessingMode>'
'<sap:MessageId>' msgid '</sap:MessageId>'
'<sap:TimeSent>' ts '</sap:TimeSent>'
'<sap:Sender>'
'<sap:Party agency="http://sap.com/xi/XI" scheme="XIParty"/>'
'<sap:Service>' bs_name '</sap:Service>'
'</sap:Sender>'
'<sap:Receiver>' INTO lv_idocout_s.
CASE control-rcvprt .
WHEN 'LS'.
CONCATENATE lv_idocout_s
'<sap:Party agency="http://sap.com/xi/XI" scheme="XIParty"/>'
'<sap:Service>' rcvprn '</sap:Service>' INTO lv_idocout_s .
WHEN OTHERS.
CONCATENATE lv_idocout_s
'<sap:Party agency="http://sap.com/xi/XI" scheme="XIParty">' rcvprn '</sap:Party>'
'<sap:Service></sap:Service>' INTO lv_idocout_s .
ENDCASE.
CONCATENATE lv_idocout_s
'</sap:Receiver>' INTO lv_idocout_s .
CASE custv-custsendns .
WHEN ' '.
CONCATENATE lv_idocout_s
'<sap:Interface namespace="urn:sap-com:document:sap:idoc:messages" >' INTO lv_idocout_s .
WHEN OTHERS.
CONCATENATE lv_idocout_s
'<sap:Interface namespace="' custv-custsendns '" >' INTO lv_idocout_s .
ENDCASE.
CASE custv-custsendif .
WHEN ' '.
CONCATENATE lv_idocout_s defaultif INTO lv_idocout_s .
WHEN OTHERS.
CONCATENATE lv_idocout_s custv-custsendif INTO lv_idocout_s .
ENDCASE.
CONCATENATE lv_idocout_s
'</sap:Interface>'
'</sap:Main>'
'<sap:ReliableMessaging xmlns:sap="http://sap.com/xi/XI/Message/30" SOAP:mustUnderstand="1" SystemAckRequested="' systemack '" SystemErrorAckRequested="' errorack '" >' INTO lv_idocout_s .
CASE custv-qidxpath .
WHEN ' ' .
CONCATENATE lv_idocout_s
'<sap:QualityOfService>ExactlyOnce</sap:QualityOfService>' INTO lv_idocout_s .
WHEN OTHERS.
CONCATENATE lv_idocout_s
'<sap:QualityOfService>ExactlyOnceInOrder</sap:QualityOfService>'
'<sap:QueueId>' queueid '</sap:QueueId>' INTO lv_idocout_s .
ENDCASE.
CONCATENATE lv_idocout_s
'</sap:ReliableMessaging>'
'<sap:DynamicConfiguration xmlns:sap="http://sap.com/xi/XI/Message/30" SOAP:mustUnderstand="1">'
'<sap:Record namespace="http://sap.com/xi/XI/System/IDoc_AAE" name="RCVPRN">' control-rcvprn '</sap:Record>'
'<sap:Record namespace="http://sap.com/xi/XI/System/IDoc_AAE" name="DOCNUMS">' control-docnum '</sap:Record>'
'<sap:Record namespace="http://sap.com/xi/XI/System/IDoc_AAE" name="AckData">' control-docnum ';' control-rcvprn '</sap:Record>'
'</sap:DynamicConfiguration>'
'<sap:HopList xmlns:sap="http://sap.com/xi/XI/Message/30" SOAP:mustUnderstand="1">'
'<sap:Hop timeStamp="' ts '" wasRead="false">'
'<sap:Engine type="AE">af.pot.pot</sap:Engine>'
'<sap:Adapter namespace="http://sap.com/xi/XI/System">IDoc_AAE</sap:Adapter>'
'<sap:MessageId>' msgid '</sap:MessageId>'
'<sap:Info>localejbs/IDocAckBean</sap:Info>'
'</sap:Hop>'
'</sap:HopList>'
'</SOAP:Header>'
'<SOAP:Body>'
idoc_string
' </SOAP:Body>'
'</SOAP:Envelope>'
INTO lv_idocout_s.

* +-------------------------------------------------------------------------------------------------+
* | Prepare output and convert from string to xstring, default UTF-8
* +-------------------------------------------------------------------------------------------------+
CLEAR outbound_xml.

outbound_xml = cl_abap_codepage=>convert_to( source = lv_idocout_s ).

* +-------------------------------------------------------------------------------------------------+
* | Error Handling
* +-------------------------------------------------------------------------------------------------+
IF errorcount <> 0.
RAISE EXCEPTION TYPE cx_abap_load_error.
ENDIF.

CATCH cx_root INTO DATA(e_text).
protocol = create_message(
iv_msgno = '006'
iv_msgv1 = 'ZCL_IM_IDOC_XML_ENVELOPE_O' ).
error = abap_true.
RETURN.
ENDTRY.

ENDMETHOD.
ENDCLASS.

Customizing


Use SQL for the first insert into ZIDOCENVELOPEOUT, e.g.
insert into sapsr3.ZIDOCENVELOPEOUT (MANDT, RCVPRN, RCVPRT, RCVPFC, MESTYP, MESCOD, MESFCT, TEST) values ('your client', 'your LS', 'LS', ' ', 'your Idoc Type', ' ', ' ', ' ');
commit;

From now on, you can edit the table in SE16, if the client settings allow it.
Consult your Basis if you face some issues.

Mandatory, if you want to apply a rule, otherwise it should also work without any transformation:
Please maintain IDocTp and CimTp like you have maintained it in WE20 partner profile to match outgoing IDocs.

Optional:
You can enter your Custom / Generic IDoc Interface name in column “CustSendIf”.
You can enter namespace of Custom / Generic IDoc Interface name in column “CustSendNs”.
You can enter your virtual receiver in column “zRcvPrn”:
–> in case of LI/KU/GP… the value will appear in party field, in case of LS it will appear in the service field.
You can enter your Xpath-Expression for creating the serialization context in column “qIdXpath”:
-> In case you fill it, the QoS will be EOIO automatically – make sure to enter an Xpath which returns a result.
-> In case you leave it empty the QoS will be EO.



Monitoring


You can monitor the assignment of queueids (from number range object), when they are created the first time in table ZIDOCENVELOUTNRO.
If you want, you can create a view joining ZIDOCENVELOPEOUT and ZIDOCENVELOUTNRO in order to suppress historic values (not part of this blog entry).



Outlook


Full function with an additional SAP PO Adapter Module in case persistence is switched on:

  1. See incoming IDocs over SAP PO – Generic IDoc Outbound Interface in IDoc monitor (KB 2345912 – IDoc Message Monitor)

  2. Be able to return Acknowledgements and monitor them using standard SAP PO IDoc Monitor (KB: 2992965 – IDoc ALEAUD)




Download Transportfile


I have them, but can unfortunately upload images and videos.

Conclusion


You are now able to send Idocs over the XML port in a generic way using the SAP PO benefits, like quality of service by configuring Xpathes in the customizing without a need to worry about the 16 character limitation and developing function modules.

Feedback and questions


Please share your feedback in the comment section.
Hint: Don't miss other and upcoming SAP PO topics, by following the tag: "SAP Prochess Orchestration"

Blog entries: https://blogs.sap.com/tags/477916618626075516391832082074785/
Q&A posts: https://answers.sap.com/tags/477916618626075516391832082074785




This post was first published on https://blogs.sap.com/
Labels in this area