- Download the WSDL
- Create the Service Consumption Model
- Add and implement a determination
- Test the service
- Summary
- Solution
In the following exercise you will learn how to call a SOAP web service and how to embed this into your inventory application by using it as part of a determination. The SOAP web service that we are going to use is a demo web service available on the SAP Gateway Demo system ES5.
- Create a text file with the extension .XML locally on your computer
- Copy the content of the WSDL file into that file. The WSDL can be found here: Link to WSDL or here raw data
In this step we will create a service consumption model based on the WSDL file that you have downloaded in the previous step.
Click to expand
-
Navigate to the folder Business Services > Service Consumption Models
-
Right-click on the folder Service Consumption Models and choose New Service Consumption Model
-
The New Service Consumption Model dialogue opens. Here enter the following data:
Name:
ZRAP620_SC_GETPRICE_###
Description:Product price from ES5
Remote Consumption Model:Web Service
(to be selected from the drop down box)Press Next
-
The WSDL file of the SOAP web service that you want to consume must be uploaded in file format. If you have not yet downloaded the WSDL file you have to do this now.
- Click Browse to select the WSDL file that you have downloaded earlier in this exercise
- Prefix:
ZRAP620###
Caution
Opposed to the prefix that we have chosen for OData Service Consumption Proxy we have to choose a leading Z.
If not, we get an error message that states:
Package ZRAP620_### is a customer package, object RAP620### is in SAP namespace. Use a valid combination of object name
-
Selection of transport request
- Select a transport request
- Press Finish
-
Service Consumption Model
The Web Service does only have one service operation
get_price
.Please note
The wizard provides code samples for each service operation. The code can be copied using the the Copy to clipboard button. We will not do this since in this exercise since we have provided a detailed code sample (see below) which is however based on the code snippet mentioned above. -
Activate your changes
Press the
button to generate the service consumption model alongside with all dependend objects.
-
Check generated objects
When refreshing your package in the Project Explorer you will notice that several objects have been generated. For those that are used to the generation of SOAP Web Service proxies in on premise systems they will look familiar.
We will use the SOAP web service to retrieve the price of a product.
Click to expand
- Add a determination in the behavior definition
- Open your behavior definition
ZRAP620_R_INVENTORYTP_###
- Add the following code snippets
- to add a determination for the field
Price
- Make the field
Price
also read-only
- to add a determination for the field
field ( readonly ) Price, //determined via determination
determination GetPrice on modify { field ProductID; }
- Select the determination name
GetPrice
and press CTRL+1 for a quick fix - Double click on the quick fix Add missing method for determination GetPrice in local handler class ...
-
Add the following code in the implementation of the method
GetPrice
.Coding explained
The following code is using large parts of the code snippets provided by the service consumption model. It has however been adjusted to fit our needs.- The destination is not retrieved by calling the method
cl_soap_destination_provider=>create_by_cloud_destination( )
but by using the methodcl_soap_destination_provider=>create_by_url( )
. This is because the destination service is not available in the ABAP trial systems in SAP Cloud Platform. - Instead of using an inline declaration for
destination
andproxy
these variables are defined beforehand. This way we can avoid that the destination and proxy object are created several times in case multiple inventories are to be created. - The data retrieved from the SOAP call is used to update the inventory data via EML.
Do not forget to search and replace the placeholder
###
with the unique number that you have chosen beforehand. - The destination is not retrieved by calling the method
METHOD GetPrice. DATA destination TYPE REF TO if_soap_destination. DATA proxy TYPE REF TO zrap620###co_epm_product_soap. DATA reported_inventory_soap LIKE reported-inventory. "Ensure idempotence READ ENTITIES OF zrap620_r_inventorytp_### IN LOCAL MODE ENTITY Inventory FIELDS ( Price ProductID ) WITH CORRESPONDING #( keys ) RESULT DATA(inventories). DELETE inventories WHERE Price IS NOT INITIAL. CHECK inventories IS NOT INITIAL. DELETE inventories WHERE ProductID =''. CHECK inventories IS NOT INITIAL. LOOP AT inventories ASSIGNING FIELD-SYMBOL(). TRY. IF destination IS INITIAL. destination = cl_soap_destination_provider=>create_by_url( i_url = 'https://sapes5.sapdevcenter.com/sap/bc/srt/xip/sap/zepm_product_soap/002/epm_product_soap/epm_product_soap' ). ENDIF. IF proxy IS INITIAL. proxy = NEW zrap620###co_epm_product_soap( destination = destination ). ENDIF. DATA(request) = VALUE zrap620###req_msg_type( req_msg_type-product = -ProductID ). proxy->get_price( EXPORTING input = request IMPORTING output = DATA(response) ). -Price = response-res_msg_type-price . -CurrencyCode = response-res_msg_type-currency. "handle response CATCH cx_soap_destination_error INTO DATA(soap_destination_error). DATA(error_message) = soap_destination_error->get_text( ). CATCH cx_ai_system_fault INTO DATA(ai_system_fault). error_message = | code: { ai_system_fault->code } codetext: { ai_system_fault->codecontext } |. CATCH zrap620###cx_fault_msg_type INTO DATA(soap_exception). error_message = soap_exception->error_text. "fill reported structure to be displayed on the UI APPEND VALUE #( uuid = -uuid %msg = new_message( id = 'ZCM_RAP_GENERATOR' number = '016' v1 = error_message "v2 = messages[ 1 ]-msgv2 "v3 = messages[ 1 ]-msgv3 "v4 = messages[ 1 ]-msgv4 severity = CONV #( 'E' ) ) %element-price = if_abap_behv=>mk-on ) TO reported_inventory_soap. "inventory entries where no price could be retrieved must not be passed to the MODIFY statement DELETE inventories INDEX sy-tabix. ENDTRY. ENDLOOP. "update involved instances MODIFY ENTITIES OF zrap620_r_inventorytp_### IN LOCAL MODE ENTITY Inventory UPDATE FIELDS ( Price CurrencyCode ) WITH VALUE #( FOR inventory IN inventories ( %tky = inventory-%tky Price = inventory-Price CurrencyCode = inventory-CurrencyCode ) ) REPORTED DATA(reported_entities). "fill reported reported = CORRESPONDING #( DEEP reported_entities ). "add reported from SOAP call LOOP AT reported_inventory_soap INTO DATA(reported_inventory). APPEND reported_inventory TO reported-inventory. ENDLOOP. ENDMETHOD.
- Activate your changes.
⚠ Caution:
The code changes described in the following are currently necessary as a workaround to avoid a short dump
Statement "INSERT " is not allowed with this status.
that will be raised because the generated code uses thestrict( 2 )
statement.
Before we can test the service we have to adapt the code of our behavior definition and our behavior projection.
Click to expand
This is because the generator uses the following statement.
strict (2);
The use of the strict(2) ;
statement inforces several checks at runtime which for example forbids the use of insert <db_table> from table <internal table>.
The underlying framework of the SOAP proxy runtime however performs such statements. To work around this problem we have either to comment out the strict statements completely or at least to use the strict ;
mode rather than the more restrictive strict (2) ;
mode.
The code of your behavior definition and the behavior projection should read as follows:
projection; //strict ( 2 ); strict ; use draft; define behavior for ZRAP620_C_INVENTORYTP_### alias Inventory use etag { use create; use update; use delete; use action Edit; use action Activate; use action Discard; use action Resume; use action Prepare; }
managed implementation in class ZRAP620_BP_InventoryTP_### unique; //strict ( 2 ); strict ; with draft; define behavior for ZRAP620_R_INVENTORYTP_### alias Inventory persistent table zrap620_inven### draft table zrap620_dinv### etag master LastChangedAt lock master total etag LocalLastChangedAt authorization master ( global ) { field ( readonly ) Price, //determined via determination InventoryID, //semantic key UUID, CreatedAt, CreatedBy, LocalLastChangedAt, LastChangedAt, LastChangedBy; field ( numbering : managed ) UUID; create; update; delete; draft action Edit; draft action Activate; draft action Discard; draft action Resume; draft determine action Prepare; determination CalculateInventoryID on save { create; } determination GetPrice on modify { field ProductID; } mapping for ZRAP620_INVEN### { UUID = UUID; InventoryID = INVENTORY_ID; ProductID = PRODUCT_ID; Quantity = QUANTITY; QuantityUnit = QUANTITY_UNIT; Price = PRICE; CurrencyCode = CURRENCY_CODE; Description = DESCRIPTION; OverallStatus = OVERALL_STATUS; CreatedBy = CREATED_BY; CreatedAt = CREATED_AT; LastChangedBy = LAST_CHANGED_BY; LastChangedAt = LAST_CHANGED_AT; LocalLastChangedAt = LOCAL_LAST_CHANGED_AT; } }
Evantually we can test our service implementation using the SAP Fiori elements preview.
Click to expand
-
Test service with Fiori Elements preview.
- Open the service binding
ZRAP620_UI_INVENTOR_O4_###
(either via Ctrl+Shift+A or via navigation in the Project Explorer) - Select the entity
Ìnventory
. - Press the Preview button
- Open the service binding
-
Create a new inventory entry and select a valid product id using the value help
-
Press the Create button
-
Create an inventory entry with an invalid ProductID (e.g. www).
Enter an invalid ProductID, e.g.
HT-1011a
The error message that we have configured if the SOAP call will not be able to find the ProductId in the backend
Product not found. Try e.g. HT-1000 :)
will not become visible since we have enabled a validation in the UI.
In this session you have learned how you can use SAP Cloud Platform, ABAP environment to implement a side-by-side extension scenarios for an SAP S/4 HANA system using the ABAP RESTful Application Programming Model.
You have retrieved data from the SAP S/4HANA system using OData and SOAP based communication to implement
- a value help to select a product for an inventory entry
- a determination for the price of a product
In a licensed SAP Cloud Platform, ABAP Environment system you would also be able to create a service consumption model for RFC function modules.