Exercise 1: Implement a Wrapper for the "Create Purchase Requisition" (BAPI_PR_CREATE) function module
When you want to perform this script in your own SAP S/4HANA system the following prerequisites must be met:
-
You have to have a system based on SAP S/4HANA 2022 or 2023 on premise or private cloud.
-
You have to have enabled Developer extensibility as described in the SAP Online Help
-
You have to apply the following notes:
Now that you're connected to your SAP S/4HANA system, go ahead with this exercise where you will learn how to deal with the situation where there is no convenient released SAP API for creating purchase requisitions.
The ABAP Cloud API Enablement Guidelines for SAP S/4HANA Cloud Private Edition and SAP S/4HANA recommend using a BAPI as an alternative to a released API, wrapping it, and then releasing the wrapper for consumption in tier 1.
In a later exercise you will then create a Shopping Cart RAP business object for a Fiori elements online shopping app in Tier 1 and integrate this wrapper to create purchase requisitions.
- How to generate a wrapper interface, a wrapper class and a factory class for the
BAPI_PR_CREATE
using transaction ACO_PROXY. - How to create an ABAP package on tier 1 (superpackage:
ZLOCAL
) - How to test that the wrapper objects have been released for consumption in tier 1.
Reminder:
Don't forget to replace all occurences of the placeholder###
with your assigned group number in the exercise steps below.
You can use the ADT function Replace All (Ctrl+F) for the purpose.
If you don't have a group number, choose a 3-digit suffix and use it for all exercises.
🔵 Click to expand!
The first step is to look for a suitable non-released API to create purchase requisitions. You can use the BAPI Explorer for this purpose. Connect to the backend of your SAP S/4HANA system and start transaction BAPI
by opening the embedded SAP GUI (Ctrl+6) and entering /nBAPI
in the command field. For the purpose of this tutorial, we will use the non-released BAPI BAPI_PR_CREATE
.
For that, switch to the Alphabetical view (1), look for the Business Object PurchaseRequisition
(2), find and click on the method CreateFromData1
(3). You can see that its function module is the BAPI_PR_CREATE
(4).
In the Documentation tab you can find more information on what the BAPI is used for (in this case: to create purchase requisitions) and you can find examples for various scenarios and how to fill the respective parameter values.
In the Tools section you can click on the Function Builder and then click on Display to see the required parameters:
The
BAPI_PR_CREATE
has aTESTRUN
parameter that can be used to call the BAPI in validation mode. Some BAPI have a similar test mode that can be used to validate input data. It is best practice to make use of this test mode, if available, as we will address in more details in a later tutorial of this group.
You will develop the wrapper in a dedicated package under the structure package ZTIER2
in your SAP S/4HANA system.
🔵 Click to expand
-
In ADT, open your SAP S/4HANA system project folder, right click on it and select New > ABAP Package and enter the following values:
- Name:
ZTIER2_###
- Superpackage:
ZTIER2
- Description:
Group ### - Tier2
.
- Name:
-
Select Add to favorite packages for easy access later on. Keep the Package Type as Development and click on Next.
-
Do not change anything in the following wizard window (where the software component HOME is selected), and click on Next.
-
Create a new transport request and give it a meaningful name such as
Tier2 development - Group ###
so that it can be more easily identified. Then click on Finish. The package will be created.
You now want to wrap the API BAPI_PR_CREATE
. For this we use the transaction ACO_PROXY which has been enhanced so that it will generate the boiler plate coding for you to build a wrapper class.
In the following we will explain in short the best practices that are behind the options you will have to choose when using transaction ACO_PROXY.
🔵 Click to expand
The interface:
Depending on your specific use-case, you normally would need to access only certain specific functionalities and methods of the BAPI you want to expose. An ABAP Interface is the perfect development object for this purpose. The interface simplifies and restricts the usage of the underlying BAPI for the specific use-case, by exposing only the parameters that are needed. As a consequence, non-wrapped functionalities are forbidden.
The wrapper class:
In addition you need a class to wrap the BAPI (implementing the interface) and implement its methods. The wrapper class has a method defined in the private section,call_bapi_pr_create
, which has access to all the parameters of the underlying BAPI. Having this type of central private method is best practice. Internally, the wrapper class has access to all the parameters and then the interface has virtual access to all of these parameters and exposes publicly only the ones that are needed depending on the specific use-case.
C1-release for use in cloud in cloud development:
Since we plan to access the wrapped BAPI in a different tier, it is good to provide the possibility to test it, and to keep wrapping-specific coding in tier 1 to a minimum. For this reason, the interface approach is recommended, and the wrapper class will not be released directly for consumption in tier 1, but rather will be accessible via a factory class that you will also be created.
The factory class: A factory class is used to control the instantiation of the wrapper class and in order to be able to use it in Tier1 it has to be released for use in tier 1.
This approach has the advantage of a clear control of when and where an instance of the wrapper class is created, and in the event in which several wrapper classes are needed all their instantiations could be handled inside one single factory class. Also, in case of wrapper classes this has the advantage that in case the wrapper class is changed throughout it's software lifecycle, at a later point in time a different class could be initialized, without changes to the consumer implementation. In this tutorial we follow the clean code best practices for ABAP development. For example: the wrapper class is ready for ABAP Unit Tests and ABAP Doc is implemented.
-
To create the interface, the class and the factory class for your BAPI start transaction ACO_PROXY.
-
Enter the following values:
A. Function Modules
- Here you can select one or more function modules that will be wrapped by one single class. Please enter here only
BAPI_PR_CREATE
.
B. Specify repository object names
- Name of a proxy class: Enter a name for the wrapper class, e.g.
ZCL_WRAP_BAPI_PR_###
. - Package: Select
ZTIER2_###
. - Create Interface: Check the check box and choose a name for the interface, e.g.
ZIF_WRAP_BAPI_PR_###
- Create Factory Class: Check the check box and choose a name for the factory class, e.g.
ZCL_F_WRAP_BAPI_PR_###
C. Options
- Leave the default value Pass destination via Constructor checked.
- Choose the radio-button Class-Based Exceptions
- Check the check box Do not create Shadows of C1 Released Types
- Check the check box C1 Release
- Check the check box Create Private Methods
- Here you can select one or more function modules that will be wrapped by one single class. Please enter here only
-
Press the green check mark
✔
in the upper left corner or F8 to continue -
Select optional values
Transaction ACO_PROXY offers you to un-select optional values that shall not be part of the public interface.
Only leave the following optional parameters of the 'BAPI_PR_CREATE' selected
- NUMBER
- PRHEADEREXP
- PRHEADER
- PRHEADERX
- TESTRUN
- PRITEMX
- RETURN
and un-select all other optional parameters.
-
Check the generated artefacts.
Hint: In case no CAL instance of a preconfigured SAP S/4HANA appliance is not used, please set up for developer extensibility to get ZTIER1
package as described in section Prerequisites.
🔵 Click to expand
-
In ADT, open your SAP S/4HANA system project folder, right click on it and select New > ABAP Package.
-
Enter the following values:
- Name:
Z_PURCHASE_REQ_###
- Superpackage:
ZTIER1
- Description:
Group ### - Tier1
.
Selec t Add to favorite packages for easy access later on. Keep the Package Type as Development and click on Next.
- Name:
-
Click on Next and then Next again. Select a suitable transport request (or create a new one if needed) and then click on Finish.
The wrapper you just created is released for consumption in tier 1. You can test this by creating a console application in tier 1 to call the wrapper.
For this you have created a dedicated package Z_PURCHASE_REQ_###
under in tier 1 by using ZTIER1
as the super-package of your package in your SAP S/4HANA System for this test.
🔵 Click to expand
- Create a class for the console application. Right click on the newly created package
Z_PURCHASE_REQ_###
and select New > ABAP Class and input the NameZCL_BAPI_WRAP_TEST_###
and a Description:
-
Click on Next, select a suitable transport request (or create a new one if needed) and then click on Finish.
-
You can check that the newly created class is a tier 1 class by checking that the ABAP Language Version is
ABAP Language for Cloud Development
in the Properties > General tab:
- Implement the newly created class as shown below. The class calls the wrapper factory class and, given some input parameter values like the delivery date and the item price, creates a purchase requisition for that specific item and prints the information to the console.
🟡📄 Click to expand and view or copy the source code!
CLASS zcl_bapi_wrap_test_### DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_bapi_wrap_test_### IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA pr_returns TYPE bapirettab.
DATA prheader TYPE zif_wrap_bapi_pr_###=>bapimereqheader .
DATA prheaderx TYPE zif_wrap_bapi_pr_###=>bapimereqheaderx .
DATA number TYPE zif_wrap_bapi_pr_###=>banfn .
DATA pritem TYPE zif_wrap_bapi_pr_###=>_bapimereqitemimp .
DATA pritemx TYPE zif_wrap_bapi_pr_###=>_bapimereqitemx .
DATA prheaderexp TYPE zif_wrap_bapi_pr_###=>bapimereqheader .
DATA(myclass) = zcl_f_wrap_bapi_pr_###=>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
testrun = abap_false
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.
Now that you've...
- created a wrapper interface, a factory class and an implementing wrapper class for the BAPI_PR_CREATE, and
- have tested the C1-released wrapper for consumption in tier 1,
you can continue with the next exercise - Exercise 2 - Create a Shopping Cart Business Object.