Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 

Caution

A basic functionality to generate such wrappers from a BAPI has been added to the transaction ACO_PROXY.

It however turned out that the generated code can lead to problems when the underlying BAPI is being changed (e.g. a field is added).

So therefore I can't recommend the use anymore, however you can play around with it and may use at least the generated type definitions.

Introduction

In a tutorial Implement a Wrapper for the "Create Purchase Requisition" (BAPI_PR_CREATE) function module that was published recently it was shown how to deal with the case in which no convenient released API is available to create purchase requisitions.

The question that came to my mind was whether there would be a way to automate the steps described in this tutorial so that creating wrappers for other BAPIs would become more easy.

This can now be done using transaction ACO_PROXY. 

 

Prerequisites

- You have to have a system based on SAP S/4HANA 2022 or 2023 on premise.
- You have to have enabled Developer extensibility
- You have to apply the following notes

3444292 - ACO Proxy creates unnecessary shadow types. - SAP for Me

3457580 - SAP ACO - Duplicate Types for Table Parameters - SAP for Me

3518177 - SAP ACO Proxy Improvements - SAP for Me

3519098 - F4: fix function module value help - SAP for Me (only relevant for SAP S/4 HANA 2023)

 

ACO_PROXY

The transaction ACO_PROXY now allows to generate a wrapper class, an C1-interface and a C1-released factory class which is the recommended approach (see the tutorial above). The C1 released factory class can then be used to intantiates the wrapper class being used in your ABAP Cloud coding.

The transaction ACO_PROXY and its underlying API now also check if a data element that is used by a non released function module itself has been released. If this is the case, no shadow type will be generated.

 

How to use the improved transaction ACO_PROXY?

First you have to start transaction ACO_PROXY.

Andre_Fischer_0-1726658492446.png

 

  1. Here you can select one or more function modules that will be wrapped by one single class. (e.g BAPI_PR_CREATE, BAPI_PR_CHANGEBAPI_PR_GETDETAIL, ...)
  2. Choose a name of a proxy class, e.g. ZAF_CL_PR_BAPI_009.
  3. Select an existing package, e.g. TEST_AF_ACO_009
  4. Check the check box Create Interface and choose a name for the interface, e.g. ZAF_IF_PR_BAPI_009
  5. Check the check box Create Factory Class and choose a name for the factory class, e.g. ZAF_CL_F_PR_BAPI_009
  6. Uncheck the check box Pass Destination via Constructor
  7. Choose the radio-button Class-Based Exceptions
  8. Check the check box Do not create Shadows of C1 Released Types
  9. Check the check box C1 Release
  10. Check the check box Create Private Methods

As described in the above mentioned tutorial the approach of using an interface and a factory class is the recommended one.

When you press the green check mark or press F8 you continue to the dialogues that allow you to de-select optional parameters from being used in the public interface of your wrapper class. 

Andre_Fischer_0-1726658961700.png

You can continue to the dialogue for the next function module by pressing the green check mark in the upper left corner of the SAPGUI screen.  

Andre_Fischer_1-1726659006078.png

Finally the generation starts.

The objects can then be checked in the target package.

Andre_Fischer_2-1726659057589.png

When you check the code of the public method you see that the private method is called with the de-selected optional parameters being commented out so that they can easily be added afterwards back to the public interface if you wish to do so. 

Andre_Fischer_0-1726659132033.png

Last not least you can check that the interface and the factory class have been C1-released.

Andre_Fischer_1-1726659255089.png

 

Hope this will help to speed up the process of creating wrappers for non-released function modules.

Call the wrapper class

The wrapper class in the sample shown above can be called as follows (see below) and would produce an out put as follows:  

Andre_Fischer_0-1726659960018.png

 

CLASS zcl_bapi_wrap_test_009 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_bapi_wrap_test_009 IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.

    DATA pr_returns TYPE bapirettab.

    DATA prheader TYPE zaf_if_pr_bapi_009=>bapimereqheader .
    DATA prheaderx TYPE zaf_if_pr_bapi_009=>bapimereqheaderx .
    DATA number  TYPE zaf_if_pr_bapi_009=>banfn  .
    DATA pritem  TYPE zaf_if_pr_bapi_009=>_bapimereqitemimp .
    DATA pritemx  TYPE zaf_if_pr_bapi_009=>_bapimereqitemx  .
    DATA prheaderexp  TYPE zaf_if_pr_bapi_009=>bapimereqheader .

    DATA(myclass) = zaf_cl_f_pr_bapi_009=>create_instance( ).

    prheader = VALUE #( pr_type = 'NB' ).
    prheaderx = VALUE #( pr_type = 'X' ).

    pritem           = VALUE #( (
                      preq_item  = '00010'
                      plant      = '1010'
                      acctasscat = 'U'
                      currency   = 'EUR'
                      deliv_date = cl_abap_context_info=>get_system_date(  ) + 14   "format: yyyy-mm-dd (at least 10 days)
                      material   = 'ZPRINTER01'
                      matl_group = 'A001'
                      preq_price = '100.00'
                      quantity   = '1'
                      unit       = 'ST'
                      pur_group = '001'
                      purch_org = '1010'
                      short_text = 'ZPRINTER01'
                    ) ).

    pritemx           = VALUE #( (
                      preq_item  = '00010'
                      plant      = 'X'
                      acctasscat = 'X'
                      currency   = 'X'
                      deliv_date = 'X'
                      material   = 'X'
                      matl_group = 'X'
                      preq_price = 'X'
                      quantity   = 'X'
                      unit       = 'X'
                      pur_group = 'X'
                      purch_org = 'X'
                      short_text = 'X'
                    ) ).

    TRY.
        myclass->bapi_pr_create(
          EXPORTING
            prheader = prheader
            prheaderx = prheaderx
            _dest_  = 'NONE'
          IMPORTING
            number   = number
            prheaderexp = prheaderexp
          CHANGING
            pritem = pritem
            pritemx = pritemx
     )
        .
      CATCH cx_aco_application_exception cx_aco_communication_failure cx_aco_system_failure INTO DATA(call_wrapper_exception).
        "handle exception
        out->write( |Exception occured: { call_wrapper_exception->get_text(  ) }| ).
    ENDTRY.
    out->write( |purchase requistion number: { number  } | ).
    LOOP AT pr_returns INTO DATA(bapiret2_line).
      out->write( |bapi_return: { bapiret2_line-message } | ).
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

Further reading

How to find SAP APIs for SAP S/4HANA 3-tier extens... - SAP Community

SAP/abap-atc-cr-cv-s4hc: ABAP test cockpit cloud readiness check variants for SAP S/4HANA Cloud (git...

 

Future Outlook

In future the idea is to offer the option to start such a generator as well in the ABAP development tools for Eclipse. This will be possible with the next S/4HANA release and the ADT generator framework.    

 

 

15 Comments
SachinArtani
Active Participant

Thank you @Andre_Fischer for this great blog.

I have one dumb question. How would these BAPI wrappers work in RAP framework without using COMMIT statement?

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

The COMMIT WORK statement is issued by the RAP framework at the end of the save sequence. You only have a problem if the function module that you are calling performs itself a commit work. In this case you would have to make sure that the BAPI call would be performed in a separate session. E.g. by using the new BGPF framework leveraging the option to also perform transaction uncontrolled caled (as of 2023) or by using a call destination 'NONE'. 

This however can in the worst case lead to inconsistent data if the RAP framework dumps but the asynchronously started call would have been started.

Fynn_Scheld
Explorer

Hi @Andre_Fischer ,

Is this the recommended way? I understand that this will technically works, but doesn't that contradict the phases of the RAP. In The Blog from Marcel Hermanns is described, that we have to do the POST-Part in the save-phase of the RAP(https://community.sap.com/t5/technology-blogs-by-sap/using-bapis-in-rap/ba-p/13560875).  I like your way with the RFC-Call with destination NONE, because I can implement it with less affort.

So my question: Is one the "better" way or does it not matter ?

 

BR

Fynn

nsathya
Explorer

Hi @Andre_Fischer 

I would like to understand more of the Service Consumption model. Am I right to understand that it is to convert any Protocol (SOAP, RFC FMs, OData) to an OData service?

If so, the once the Service Consumption model is created, what happens next? do we create a service binding similar to RAP's Service definition?

What do with do with the generated classes out of your program?

Thanks,

Sathya

Timo_John1
Active Participant

Great investment Andre, 
thanks for sharing such tool. it will help very much to create uniform pattern based wrappers. 
I like it a lot. 

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

@fynn_scheld 

The recommended way is to perform the call within the save sequence in order to guarantee transactional consistency. 

Using Destination NONE is a workaround for a bapi that doesn't behave well and that performs commits.

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

@https://community.sap.com/t5/user/viewprofilepage/user-id/158197

Please post your question in the q&a area since if is not related to this blog post 

BlackmanCC
Explorer

Hi @Andre_Fischer 

thank you for your great blog!

I also have to deal with BADIs with implicit commit or without test mode. I would always break up the Badi code and use the underlying function modules that the Badi uses. 

This variant is also not optimal, but I absolutely want to avoid possible data inconsistencies than can occur using RFC-Call with destination NONE.

 

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

Hi @BlackmanCC ,

are the underlying function modules RFC enabled?
Then you could use this wrapper to wrap those instead of the BAPI. 

Instead of destination 'NONE' it is also possible to call a class via BGPF (background processing framework) as of SAP S/4HANA 2023. There is an option to perform such a call without transactional control as an alternative to the use of destination 'NONE'.

kasithunuguntla
Participant

Hi @Andre_Fischer, It was fantastic information. We will start using this tool going forward. Thanks so much. I have tried this tool using Function Module SATC_CI_GET_RESULT which actually failed with Syntax Errors. I corrected them manually but just want to bring to your notice so that the bug can be fixed.  There are two export parameters with type "i " which are not actually defined in the Interface by the tool but referenced in the Class. I changed it from ZIF_WRAP_SATC~i to just "i" and it worked fine. 

Let me know if you need more information.

kasithunuguntla_0-1717416232523.png

 

Andre_Fischer
Product and Topic Expert
Product and Topic Expert

Hi @kasithunuguntla ,

thank you very much for pointing me to this issue.

I have fixed it 

The code is now checked for built in types.

Kind regards, 

Andre

ArneVH
Explorer

Hi @Andre_Fischer,

Can we expect a similar tool for classes in the (near) future?

Thanks!

Update: We had the opportunity to contact SAP directly for some questions and the answer to this question was: no such tool is currently planned.

Marcal_Oliveras
Active Contributor

I hope there is soon a similar tool for classes as @ArneVH already requested. I was just looking for it today to add a wrapper for the unreleased cl_outbound_provider_http as suggested here: ABAP Cloud - HTTP Client (or the classic http client)

MRobalinho
SAP Champion
SAP Champion

Thanks for sharing

In Prerequisite it says only for on premise systems. Is it applicable for on Private Cloud as well?

Labels in this area