A custom web service to post functional acknowledgement to Application Interface Framework of S/4

Estimated read time 12 min read

Introduction

Recently SAP released several SOAP APIs (e.g. Order Confirmation, Customer Invoice and Outbound Delivery) for B2B scenarios, and standard interfaces of SAP Application Interface Framework (AIF) were also delivered by SAP accordingly. The APIs and AIF interfaces could be leveraged in B2B integration instead of using classical IDOC framework.

However, there is one general requirement in B2B integration, which is receiving functional acknowledgement from receivers (external business partners). In classical IDOC framework ALEAUD could be used, processing results could be sent back via IDOC ALEAUD and update the status of original outbound IDOCs accordingly (e.g. status 11 and 12).

In my blog, I would like to provide a similar solution like ALEAUD for those SOAP APIs, hereby customers could still receive functional acknowledgement when leveraging “modern” APIs in B2B scenarios.

Solution Design Concept

In AIF, there is a standard solution for Error Forwarding from Cloud Integration to S/4HANA, via a web service Error_Propagation_Request_In, errors in Cloud Integration could be posted in the Message Monitoring of AIF. But the web service is for inbound AIF interfaces, in case of a message to be posted in S/4HANA but get failure in Cloud Integration, the errors could be posted to AIF as an error message of the relevant AIF interface, so the service always creates a new AIF message with “technical error”.

In my solution, which is receiving acknowledgement for outbound scenarios, I would create a custom web service by reusing the same message type of standard Error_Propagation_Request_In, within the service implementing class I’ll call the same class (/aif/cl_enabler_cpi) called in the standard service, but update the existing outbound AIF message with the status and logs passed in the service payload.

Service Definition

Firstly, create a custom web service definition via transaction SPROXY_START. One of prerequisite is creating a custom namespace via transaction SPXNGENAPPL under Backend Metadata Repository:

In SPROXY_START, create a service provider by using “Create with WIZARD” (Shift+F5):

After completing the wizard, a custom web service has been defined (in my case the service was named Application_Acknowledgement_In):

Go to tab “Internal View”, create an operation via “Add Operation” (right click menu), and then “Set Request” and assign standard Message Type Error_Propagation_Request, “Add Fault” and assign standard Fault Message Type Error_Propagation_Fault, the service definition is completed. Save and activate the service.

Next, navigate to the auto-generated implementing class, adding below codes to the method:

  METHOD zii_application_acknowledgemen~application_acknowledgement.
*** **** INSERT IMPLEMENTATION HERE **** ***
    TYPES:
      BEGIN OF lty_msg_long,
        msgv1 TYPE symsgv,
        msgv2 TYPE symsgv,
        msgv3 TYPE symsgv,
        msgv4 TYPE symsgv,
      END OF lty_msg_long.
    DATA:
      lr_enabler_cpi TYPE REF TO /aif/cl_enabler_cpi,
      lr_system_uuid TYPE REF TO if_system_uuid,
      lv_uuid        TYPE sysuuid_c32,
      lv_status      TYPE /aif/proc_status,
      lv_msg_status  TYPE /aif/proc_status,
      ls_log_message TYPE bal_s_msg,
      ls_bal_context TYPE /aif/bal_context,
      ls_msg_long    TYPE lty_msg_long.

    DATA(ls_ep_message) = VALUE /aif/ep_message(
            message_processing_log_id = input-error_propagation_request-message_processing_log_id
            mpl_correlation_id        = input-error_propagation_request-mpl_correlation_id
            application_id            = input-error_propagation_request-application_id
            tenant_name               = input-error_propagation_request-tenant_name
            iflow_id                  = input-error_propagation_request-iflow_id
            namespace                 = input-error_propagation_request-namespace
            interface_name            = input-error_propagation_request-interface_name
            interface_version         = input-error_propagation_request-interface_version
            error_message             = input-error_propagation_request-error_message
            ).

    lv_uuid = input-error_propagation_request-application_id.
    lv_status = ls_ep_message-error_message+0(1).

    TRY.
        CREATE OBJECT lr_enabler_cpi
          EXPORTING
            iv_msgguid   = lv_uuid
            iv_ns        = ls_ep_message-namespace
            iv_ifname    = Ls_ep_message-interface_name
            iv_ifversion = ls_ep_message-interface_version.

        DATA(lt_log_message) = lr_enabler_cpi->prepare_log_messages( ls_ep_message ).
        DELETE lt_log_message FROM 1 TO 2.
        DELETE lt_log_message WHERE msgty = ‘I’ AND msgno = ‘005’.
        ls_msg_long(113) = ls_ep_message-error_message.
        IF lv_status EQ ‘S’.
          lv_msg_status = ‘I’.
        ELSE.
          lv_msg_status = lv_status.
        ENDIF.
        ls_log_message = VALUE bal_s_msg( context-tabname = ‘/AIF/BAL_CONTEXT’ context-value = ls_bal_context msgid = ‘/AIF/CPI_INTEGRATION’ msgty = lv_msg_status msgno = ‘006’ msgv1 = ls_msg_long-msgv1 msgv2 = ls_msg_long-msgv2 msgv3 =
ls_msg_long-msgv3 ).
        INSERT ls_log_message INTO TABLE lt_log_message.

        TEST-SEAM call_base_enabler_update.
          CALL METHOD lr_enabler_cpi->/aif/if_enabler_base~update
            EXPORTING
              iv_message_status_flag = lv_status
              it_log_messages        = lt_log_message
              iv_user_name           = cl_abap_syst=>get_user_name( )
              iv_create_date         = sy-datum
              iv_create_time         = sy-uzeit.
        END-TEST-SEAM.
      CATCH cx_root INTO DATA(lr_root).
        RAISE EXCEPTION TYPE /aif/cx_error_propagation_faul EXPORTING previous = lr_root.
    ENDTRY.
  ENDMETHOD.

Comments: To save effort I was using /aif/cl_enabler_cpi->prepare_log_messages to prepare log messages, in actual implementation you could create your own log messages without using the method.

Test Scenario

You could publish the web service via SOAMANAGER so it could be called by soapUI or any applications/middleware, below are explanations of how to fill the payload:

MessageProcessingLogID and MplCorrelationID – if you’re using Cloud Integration to call the service, those IDs are from the Cloud Integration message, standard Error Propagation service stores the IDs to avoid duplicate posting, here since we’re updating the existing AIF messages, those IDs could be dummy.

ApplicationID – I use the field to store the original outbound message ID, the outbound messages pass the message ID in the message header, receivers have to store the ID and pass it back in the acknowledgement, it is mandatory for the solution.

TenantName and IFlowID – if you’re using Cloud Integration, those are information of your tenant and iFlow to call the service, if you’re not using Cloud Integration, those fields could be dummy

Namespace, InterfaceName and InterfaceVersion – the AIF interface which the original outbound messages are belonged to.

ErrorMessage – I’m assuming the error message returning in format <status>:<logs>, <status> has to be one of the AIF message status (W/S/E/A) which would be used to update the status of original AIF messages.

Note: payload of standard Error Propagation service was explained in the blog for your reference.

For my test case, I had a message (000003) sent to the receiver successfully:

Then assuming the receiver return an error with below payload:

After posting the message shown with application error in AIF message monitoring:

Summary

This blog post gave an introduction on building a custom web service to receive functional acknowledgement from external receivers/middleware for outbound AIF messages and update the message status and logs in AIF Message Monitor. This is a very simple implementation just for reference and therefore more comprehensive and standardized implementation required in actual project.

 

​ IntroductionRecently SAP released several SOAP APIs (e.g. Order Confirmation, Customer Invoice and Outbound Delivery) for B2B scenarios, and standard interfaces of SAP Application Interface Framework (AIF) were also delivered by SAP accordingly. The APIs and AIF interfaces could be leveraged in B2B integration instead of using classical IDOC framework.However, there is one general requirement in B2B integration, which is receiving functional acknowledgement from receivers (external business partners). In classical IDOC framework ALEAUD could be used, processing results could be sent back via IDOC ALEAUD and update the status of original outbound IDOCs accordingly (e.g. status 11 and 12).In my blog, I would like to provide a similar solution like ALEAUD for those SOAP APIs, hereby customers could still receive functional acknowledgement when leveraging “modern” APIs in B2B scenarios.Solution Design ConceptIn AIF, there is a standard solution for Error Forwarding from Cloud Integration to S/4HANA, via a web service Error_Propagation_Request_In, errors in Cloud Integration could be posted in the Message Monitoring of AIF. But the web service is for inbound AIF interfaces, in case of a message to be posted in S/4HANA but get failure in Cloud Integration, the errors could be posted to AIF as an error message of the relevant AIF interface, so the service always creates a new AIF message with “technical error”.In my solution, which is receiving acknowledgement for outbound scenarios, I would create a custom web service by reusing the same message type of standard Error_Propagation_Request_In, within the service implementing class I’ll call the same class (/aif/cl_enabler_cpi) called in the standard service, but update the existing outbound AIF message with the status and logs passed in the service payload.Service DefinitionFirstly, create a custom web service definition via transaction SPROXY_START. One of prerequisite is creating a custom namespace via transaction SPXNGENAPPL under Backend Metadata Repository:In SPROXY_START, create a service provider by using “Create with WIZARD” (Shift+F5):After completing the wizard, a custom web service has been defined (in my case the service was named Application_Acknowledgement_In):Go to tab “Internal View”, create an operation via “Add Operation” (right click menu), and then “Set Request” and assign standard Message Type Error_Propagation_Request, “Add Fault” and assign standard Fault Message Type Error_Propagation_Fault, the service definition is completed. Save and activate the service.Next, navigate to the auto-generated implementing class, adding below codes to the method:  METHOD zii_application_acknowledgemen~application_acknowledgement.*** **** INSERT IMPLEMENTATION HERE **** ***    TYPES:      BEGIN OF lty_msg_long,        msgv1 TYPE symsgv,        msgv2 TYPE symsgv,        msgv3 TYPE symsgv,        msgv4 TYPE symsgv,      END OF lty_msg_long.    DATA:      lr_enabler_cpi TYPE REF TO /aif/cl_enabler_cpi,      lr_system_uuid TYPE REF TO if_system_uuid,      lv_uuid        TYPE sysuuid_c32,      lv_status      TYPE /aif/proc_status,      lv_msg_status  TYPE /aif/proc_status,      ls_log_message TYPE bal_s_msg,      ls_bal_context TYPE /aif/bal_context,      ls_msg_long    TYPE lty_msg_long.    DATA(ls_ep_message) = VALUE /aif/ep_message(            message_processing_log_id = input-error_propagation_request-message_processing_log_id            mpl_correlation_id        = input-error_propagation_request-mpl_correlation_id            application_id            = input-error_propagation_request-application_id            tenant_name               = input-error_propagation_request-tenant_name            iflow_id                  = input-error_propagation_request-iflow_id            namespace                 = input-error_propagation_request-namespace            interface_name            = input-error_propagation_request-interface_name            interface_version         = input-error_propagation_request-interface_version            error_message             = input-error_propagation_request-error_message            ).    lv_uuid = input-error_propagation_request-application_id.    lv_status = ls_ep_message-error_message+0(1).    TRY.        CREATE OBJECT lr_enabler_cpi          EXPORTING            iv_msgguid   = lv_uuid            iv_ns        = ls_ep_message-namespace            iv_ifname    = Ls_ep_message-interface_name            iv_ifversion = ls_ep_message-interface_version.        DATA(lt_log_message) = lr_enabler_cpi->prepare_log_messages( ls_ep_message ).        DELETE lt_log_message FROM 1 TO 2.        DELETE lt_log_message WHERE msgty = ‘I’ AND msgno = ‘005’.        ls_msg_long(113) = ls_ep_message-error_message.        IF lv_status EQ ‘S’.          lv_msg_status = ‘I’.        ELSE.          lv_msg_status = lv_status.        ENDIF.        ls_log_message = VALUE bal_s_msg( context-tabname = ‘/AIF/BAL_CONTEXT’ context-value = ls_bal_context msgid = ‘/AIF/CPI_INTEGRATION’ msgty = lv_msg_status msgno = ‘006’ msgv1 = ls_msg_long-msgv1 msgv2 = ls_msg_long-msgv2 msgv3 =ls_msg_long-msgv3 ).        INSERT ls_log_message INTO TABLE lt_log_message.        TEST-SEAM call_base_enabler_update.          CALL METHOD lr_enabler_cpi->/aif/if_enabler_base~update            EXPORTING              iv_message_status_flag = lv_status              it_log_messages        = lt_log_message              iv_user_name           = cl_abap_syst=>get_user_name( )              iv_create_date         = sy-datum              iv_create_time         = sy-uzeit.        END-TEST-SEAM.      CATCH cx_root INTO DATA(lr_root).        RAISE EXCEPTION TYPE /aif/cx_error_propagation_faul EXPORTING previous = lr_root.    ENDTRY.  ENDMETHOD.Comments: To save effort I was using /aif/cl_enabler_cpi->prepare_log_messages to prepare log messages, in actual implementation you could create your own log messages without using the method.Test ScenarioYou could publish the web service via SOAMANAGER so it could be called by soapUI or any applications/middleware, below are explanations of how to fill the payload:MessageProcessingLogID and MplCorrelationID – if you’re using Cloud Integration to call the service, those IDs are from the Cloud Integration message, standard Error Propagation service stores the IDs to avoid duplicate posting, here since we’re updating the existing AIF messages, those IDs could be dummy.ApplicationID – I use the field to store the original outbound message ID, the outbound messages pass the message ID in the message header, receivers have to store the ID and pass it back in the acknowledgement, it is mandatory for the solution.TenantName and IFlowID – if you’re using Cloud Integration, those are information of your tenant and iFlow to call the service, if you’re not using Cloud Integration, those fields could be dummyNamespace, InterfaceName and InterfaceVersion – the AIF interface which the original outbound messages are belonged to.ErrorMessage – I’m assuming the error message returning in format <status>:<logs>, <status> has to be one of the AIF message status (W/S/E/A) which would be used to update the status of original AIF messages.Note: payload of standard Error Propagation service was explained in the blog for your reference.For my test case, I had a message (000003) sent to the receiver successfully:Then assuming the receiver return an error with below payload:After posting the message shown with application error in AIF message monitoring:SummaryThis blog post gave an introduction on building a custom web service to receive functional acknowledgement from external receivers/middleware for outbound AIF messages and update the message status and logs in AIF Message Monitor. This is a very simple implementation just for reference and therefore more comprehensive and standardized implementation required in actual project.   Read More Technology Blogs by SAP articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author