Skip to Content

In the previous blog, we saw how a standard form template can be extended for Custom Fields with the help of Custom Logic and external HTTP call. In this blog, we will see how to do mass update using In-app extensibility features of Custom Business Objects and HTTP call.

In this business scenario, rebate needs to be applied to Sales Order items after it has been created. We will be using the Sales Order API to achieve this functionality. In this example, we assume that different rebate rates need to be applied for different line items. It is also assumed that pre-requisites like discount pricing condition (DPG4) are maintained in the pricing procedure.

Create Communication Arrangements to enable HTTP Call

1. Login with the user having role SAP_BR_ADMINISTRATOR.

2. Create a Communication User using the app Maintain Communication Users under the catalog Communication Management. In this example we create a user named HTTP_USER.

3. Create a Communication System using the app Communication Systems under the catalog Communication Management with following details.

System ID: INT_HTTP

System Name: INT_HTTP

  • Enter the following details for the Communication System and click Save.

Host Name: myXXXXXX-api.s4hana.ondemand.com (Replace XXXXXX with your tenant URL)

HTTPS Port: 443

User for Inbound Communication: HTTP_USER

User for Outbound Communication: HTTP_USER

 

4. Create a Custom Communication Scenario using the app Custom Communication Scenarios under the catalog Extensibility.

  • Create a new Communication Scenario with the following details.

Communication Scenario ID: YY1_INT_HTTP

Description: Internal HTTP

  • Create an Outbound Service with the following details.

Description: INT_HTTP

Outbound Service ID: YY1_INT_HTTP_REST

URL Path: /sap/opu/odata/sap

5. Create Communication Arrangement using the app Communication Arrangements under the catalog Communication Management.

  • Click New, enter the following details and click Create.

Scenario: YY1_INT_HTTP

Arrangement Name: YY1_INT_HTTP

  • In the details page, enter the details shown below and click Save.

  • Repeat Step 5 for Communication Scenario SAP_COM_0109. The Inbound User will be HTTP_USER.

 

Create a Custom Business Object to facilitate the Rebate change

The details of creating a Custom Business Object with child nodes is not covered in detail here. For more information, you can refer this tutorial series. Include the Custom Business Object in appropriate catalog (Preferably related to Sales Order) for it to be displayed as a fiori tile.

Create a custom business object with the following structure and actions. We will primarily be focusing on the Action Apply Rebate which will make the HTTP call.

Custom Business Object: SALESORDER

Nodes and Structures:

Actions:

Code Snippet for Get Items:

This method would populate the Sales Order line items. This code uses the functionality of creating child entities from parent entity.

TRY.
    DATA lv_so TYPE yy1_kr_salesorder.
    lv_so = salesorder-id.
    DATA(lo_salesorder) = write->get_root(
        business_object_id = 'YY1_SALESORDER'
        key                = lv_so ).
    CATCH cx_cbo_write_not_existing.
  RETURN.
ENDTRY.

lo_salesorder->delete_children( node_id = 'Items' ).

SELECT * INTO TABLE @DATA(lt_soitems) FROM i_salesdocumentitem WHERE salesdocument = @salesorder-id.
DATA ls_soitem TYPE i_salesdocumentitem.
DATA ls_data TYPE yy1_items_salesorder.
SELECT * INTO TABLE @DATA(lt_rebate) FROM i_salesdocitempricingelement WHERE salesdocument = @salesorder-id
AND conditiontype = 'DPG4'.
DATA ls_rebate TYPE i_salesdocitempricingelement.

LOOP AT lt_soitems INTO ls_soitem.
READ TABLE lt_rebate INTO ls_rebate WITH KEY salesdocumentitem = ls_soitem-salesdocumentitem.
ls_data = VALUE #( itemno = ls_soitem-salesdocumentitem
material = ls_soitem-material
quantity = ls_soitem-requestedquantity
netvalue_c = ls_soitem-transactioncurrency
netvalue_v = ls_soitem-netamount
rebate = ls_rebate-conditionratevalue ).
lo_salesorder->create_child(
  EXPORTING
    node_id = 'Items'
    data    = ls_data
).
ENDLOOP.

Code Snippet for Apply Rebate:

The external HTTP call is made here. As this is a POST request, we need to fetch the CSRF token first. The payload is dynamically created before the POST call.

CHECK cl_ble_http_client=>is_service_available(
    communication_scenario = 'YY1_INT_HTTP'
    outbound_service       = 'YY1_INT_HTTP_REST'
) = abap_true.

DATA(lo_client) = cl_ble_http_client=>create(
    communication_scenario = 'YY1_INT_HTTP'
    outbound_service       = 'YY1_INT_HTTP_REST'
).

DATA(request) = cl_ble_http_request=>create( ).
DATA lv_s2 TYPE string VALUE 'API_SALES_ORDER_SRV/A_SalesOrder?$top=1&$format=json'.
request->set_header_parameter( exporting name = 'X-CSRF-TOKEN' value = 'FETCH' ).
request->set_method( 'GET' )->set_resource_extension( lv_s2 ).
TRY .
    DATA(response) = lo_client->send( request ).
    DATA(lv_csrf) = response->get_header_parameter( 'x-csrf-token' ).
    CATCH cx_ble_http_exception INTO DATA(l5).
ENDTRY.

DATA: lv_pl1 TYPE string value '--batch  Content-Type: multipart/mixed; boundary=changeset',
      lv_pl2 TYPE string value '--changeset  Content-Type: application/http',
      lv_pl3 TYPE string value 'Content-Transfer-Encoding: binary',
      lv_pl4 TYPE string,
      lv_pl5 TYPE string value 'Content-Type: application/json',
      lv_pl6 TYPE string,
      lv_pl7 TYPE string value '--changeset--',
      lv_pl8 TYPE string value '--batch--',
      lv_payload TYPE string,
      lv_pl41 TYPE string value 'PATCH A_SalesOrderItemPrElement(SalesOrder=%27',
      lv_pl42 TYPE string value '%27,SalesOrderItem=%27',
      lv_pl43 TYPE string value '%27,PricingProcedureStep=%27180%27,PricingProcedureCounter=%271%27) HTTP/1.1',
      lv_pl61 TYPE string value '{ "ConditionRateValue" : "',
      lv_pl62 TYPE string value '" }'.

DATA(lt_items) = association->to_items( ).
DATA ls_items LIKE LINE OF lt_items.
DATA lv_rebate_str TYPE string.

LOOP AT lt_items into ls_items.

CONCATENATE lv_pl41 salesorder-id lv_pl42 ls_items-items-itemno lv_pl43 INTO lv_pl4.
lv_rebate_str = ls_items-items-rebate.
CONDENSE lv_rebate_str..
CONCATENATE lv_pl61 '-' lv_rebate_str lv_pl62 INTO lv_pl6.
CONCATENATE lv_pl1 cl_abap_char_utilities=>cr_lf lv_pl2 lv_pl3 cl_abap_char_utilities=>cr_lf
lv_pl4 lv_pl5 cl_abap_char_utilities=>cr_lf lv_pl6 cl_abap_char_utilities=>cr_lf
lv_pl7 lv_pl8 INTO lv_payload SEPARATED BY cl_abap_char_utilities=>cr_lf.

DATA(request1) = cl_ble_http_request=>create( ).
DATA lv_s1 TYPE string VALUE 'API_SALES_ORDER_SRV/$batch'.
request1->set_header_parameter( exporting name = 'x-csrf-token' value = lv_csrf ).
request1->set_content_type( 'multipart/mixed; boundary=batch' ).
request1->set_method( 'POST' )->set_resource_extension( lv_s1 ).
request1->set_body( lv_payload ).
TRY .
    DATA(response1) = lo_client->send( request1 ).
    CATCH cx_ble_http_exception INTO DATA(lx1).
ENDTRY.
ENDLOOP.

Note: If there are errors in the payload, you should ideally be able to get them in http_exception.

Test the Scenario

  1. Login to SAP S/4HANA Cloud with user having role SAP_BR_INTERNAL_SALES_REP.
  2. Choose the app Create Sales Order to create a sales order with couple of items.
  3. Open the Custom Business Object app Sales Orders. Make a new entry with the Sales Order created in the previous step. Choose Save.
  4. Choose Get Items to load the Sales Order items. This can be viewed by navigating to the next screen.
  5. Choose Edit and enter the discount percentage. Choose Save and Apply Rebate. 
  6. Choose the Display Sales Order app and navigate to the Sales Order Item pricing conditions to check if the discount was applied. 

 

Disclaimer: The main emphasis of this blog is to show how to use S/4HANA Cloud APIs using In-App extension itself. However, before doing any data change using such an approach, it is always advisable to validate the process with a functional expert. 

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply