https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/ABAP-RESTful-Application-Programming-Model-blog-posts.xml SAP Community - ABAP RESTful Application Programming Model 2024-05-10T05:00:07.550086+00:00 python-feedgen ABAP RESTful Application Programming Model blog posts in SAP Community https://community.sap.com/t5/technology-blogs-by-members/using-prechecks-and-how-to-combine-them/ba-p/13600717 Using Prechecks and how to combine them. 2024-02-09T16:00:46.387000+01:00 Sschlegel https://community.sap.com/t5/user/viewprofilepage/user-id/37925 <P>A very common activity when working with RAP and Fiori Elements is the validation of user input. Unfortunately, validations are only ever carried out when saving and you often want to give the user feedback earlier - especially when using draft mode. What is the best way to do this? The way to go in this case is to use <A href="https://help.sap.com/docs/abap-cloud/abap-rap/operation-precheck#prechecks-in-ui-scenario" target="_self" rel="noopener noreferrer">prechecks</A>. So far all good, but unfortunately the wizard makes it a bit more difficult than necessary, because after defining the prechecks in the behavior definition (or the behavior projection, which I prefer to use) it generates 2 methods if you want to perform the same check for CREATE and UPDATE - e.g. that the customer number should always be filled.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>define behavior for ZC_MyEntity alias Entity { use create ( augment, precheck ); use update ( augment, precheck ); use delete; }</code></pre><P>&nbsp;</P><P>The following is generated here:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> METHODS precheck_create FOR PRECHECK IMPORTING entities FOR CREATE Entity. METHODS precheck_update FOR PRECHECK IMPORTING entities FOR UPDATE Entity.</code></pre><P>&nbsp;</P><P>However, a look at the documentation shows that there is a simpler way:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> METHODS precheck FOR PRECHECK IMPORTING entities_create FOR CREATE Entity entities_update FOR UPDATE Entity.</code></pre><P>&nbsp;</P><P>So that you only have to go through one loop, you then pack the almost identical structures together.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> METHOD precheck. DATA(entities_check) = entities_create. entities_check = VALUE #( BASE entities_check FOR entity_update IN entities_update ( CORRESPONDING #( entity_update ) ) ). LOOP AT entities_check INTO DATA(entitiy_check). ENDLOOP. ENDMETHOD.</code></pre><P>&nbsp;</P><P>This approach saves code duplication and also makes maintenance easier.</P><H2 id="toc-hId-986004137"><STRONG>Important</STRONG></H2><P>If you use DRAFT, then, depending on the use case, you unfortunately still have to read the "unchanged fields" during the update, as only the delta (i.e. the changed fields) is transferred via a PATCH. This is hopefully done before the loop - <A href="https://community.sap.com/t5/technology-blogs-by-members/prechecks-on-update-in-rap-when-using-draft/ba-p/13601689#M165936" target="_self">you can find here my personal favorit on how to this</A>.</P><P>I hope this helps you and makes your life easier - enjoy&nbsp;<span class="lia-unicode-emoji" title=":grinning_face:">😀</span></P><P>&nbsp;</P><P>&nbsp;</P> 2024-02-09T16:00:46.387000+01:00 https://community.sap.com/t5/technology-blogs-by-members/prechecks-on-update-in-rap-when-using-draft/ba-p/13601689 Prechecks on Update in RAP when using DRAFT 2024-02-11T15:58:56.151000+01:00 Sschlegel https://community.sap.com/t5/user/viewprofilepage/user-id/37925 <P>I already wrote a small <A href="https://community.sap.com/t5/technology-blogs-by-members/using-prechecks-and-how-to-combine-them/ba-p/13600717" target="_self">Post on Combination of Prechecks</A> - but when using Prechecks&nbsp; in DRAFT- enabled scenarios, you'll face an other Problem: Updates only contain changed fields - how to deal with it?</P><P>First, we look at the definition. This can be done both at the level of the behavior definition and at the level of the behavior projection - I personally usually prefer this in the projection, as it makes sense to map the check again as a Determination on Save, so that a clean integrity of the BO is ensured:</P><pre class="lia-code-sample language-abap"><code>define behavior for ZC_MyEntity alias Header { use create ( augment, precheck ); use update ( augment, precheck ); use delete; ... }</code></pre><P>After defining the behavior, we come to the method definition:</P><pre class="lia-code-sample language-abap"><code> METHODS precheck FOR PRECHECK IMPORTING entities_create FOR CREATE Header entities_update FOR UPDATE header.</code></pre><P>And yes: last but not least, implementation:</P><pre class="lia-code-sample language-abap"><code> DATA(entities_check) = entities_create. LOOP AT entities_update INTO DATA(entity_update). READ ENTITIES OF ZC_MyEntity IN LOCAL MODE ENTITY Header ALL FIELDS WITH VALUE #( ( %tky = entity_update-%tky ) ) RESULT DATA(header_read). IF lines( header_read ) = 0. CONTINUE. ENDIF. APPEND INITIAL LINE TO entities_check ASSIGNING FIELD-SYMBOL(&lt;entity_check&gt;). &lt;entity_check&gt; = CORRESPONDING #( header_read[ 1 ] ). &lt;entity_check&gt; = CORRESPONDING #( BASE ( &lt;entity_check&gt; ) entity_update USING CONTROL ). ENDLOOP. LOOP AT entities_check INTO DATA(entity_check). * Here are our checks! ENDLOOP. </code></pre><P>What do we do here?</P><UL><LI>Line 1: Here we define a variable that should finally contain ALL entries that we want to check</LI><LI>Line 3: We loop over the ENTITIES_UPDATE, as we have to read the other contents for these</LI><LI>Line 5: Now comes a READ ENTITIES - depending on where we implement our precheck, on the ZI_* or the ZC_*</LI><LI>Line 7: This is particularly important for DRAFT newcomers! We do not use %KEY, but %TKY - we may want to read the content of the DRAFT - and not what is only activated.</LI><LI>Line 10: As always, we should also make sure that there is already something and that we are not in the first change</LI><LI>Line 17: Now we combine "old values" and "new values" - we use the CONTROL flags that RAP provides us with instead of performing a manual comparison</LI><LI>Line 22ff: Now we can let off steam with all our magic <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span></LI></UL><P><SPAN>Enjoy!</SPAN></P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2024-02-11T15:58:56.151000+01:00 https://community.sap.com/t5/application-development-blog-posts/crud-operation-using-restful-api-in-sap/ba-p/13600192 CRUD Operation Using RESTful API in SAP 2024-02-13T09:02:35.581000+01:00 Naveen_n https://community.sap.com/t5/user/viewprofilepage/user-id/1388970 <P>Title:<STRONG><SPAN> CRUD Operation Using RESTful API in SAP</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Introduction:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>SAP (Systems, Applications, and Products in Data Processing) is a renowned enterprise resource planning (ERP) software and integrating RESTful APIs with SAP can significantly enhance its capabilities. In this blog, we will delve into the basics of CRUD operations in REST API within the SAP environment, exploring the fundamental concepts and demonstrating how to perform Create, Read, Update, and Delete operations seamlessly.</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Understanding CRUD Operations:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>CRUD operations form the core of database interactions and are crucial for any application's functionality. In a REST API context, CRUD corresponds to the following HTTP methods:</SPAN><SPAN>&nbsp;</SPAN></P><OL><LI><STRONG><SPAN>Create (POST):</SPAN></STRONG><SPAN> This method is used to add new data to the server.</SPAN><SPAN>&nbsp;</SPAN></LI></OL><OL><LI><STRONG><SPAN>Read (GET):</SPAN></STRONG><SPAN> Retrieve information from the server without modifying it.</SPAN><SPAN>&nbsp;</SPAN></LI></OL><OL><LI><STRONG><SPAN>Update (PUT):</SPAN></STRONG><SPAN> Modify existing data on the server.</SPAN><SPAN>&nbsp;</SPAN></LI></OL><OL><LI><STRONG><SPAN>Delete (DELETE):</SPAN></STRONG><SPAN> Remove data from the server.</SPAN><SPAN>&nbsp;</SPAN></LI></OL><P><SPAN>Setting Up SAP for REST API Integration:</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Before diving into CRUD operations, you need to ensure that your SAP environment is set up to support REST API integration. This may involve configuring SAP Gateway, enabling web services, and securing communication between SAP and your application.</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>In this blog, we'll explore how to Perform CRUD operation from Restful API</SPAN></STRONG><SPAN>&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Generally REST describes a machine-to-machine interface. In Web development, REST allows content to be rendered when it is requested, often referred to as Dynamic Content. RESTful Dynamic content uses server-side rendering to generate a Web site and send the content to the requesting Web browser, which interprets the server’s code and renders the page in the user’s Web browser.</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>PROCEDURE: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Here We have to create structure and table type for sales order line-item condition&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_0-1707457624832.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63092i43699C8DB70A1051/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_0-1707457624832.png" alt="Naveen_n_0-1707457624832.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_1-1707457624835.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63091i17091B60A9E0335A/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_1-1707457624835.png" alt="Naveen_n_1-1707457624835.png" /></span></P><P><SPAN>Here we have to create structure and table type for Sales order line item and&nbsp; pass Deep component(Structure which includes a Table type). </SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_2-1707457624839.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63093iE57BFB27C4829AA0/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_2-1707457624839.png" alt="Naveen_n_2-1707457624839.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_3-1707457624842.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63094iA8CD6DD11E7588D6/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_3-1707457624842.png" alt="Naveen_n_3-1707457624842.png" /></span></P><P><SPAN>Here we have to create Structure for sales order header information and here we have to pass&nbsp; Deep component(Structure which includes a Table type).</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_4-1707457624845.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63095i8ABAC5AA74697A5D/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_4-1707457624845.png" alt="Naveen_n_4-1707457624845.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_5-1707457624849.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63096i278B9A34D8C8661F/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_5-1707457624849.png" alt="Naveen_n_5-1707457624849.png" /></span></P><P><SPAN>In SE24 create a class for request provider and request handler class.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_6-1707457624852.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63097i721F8D531BB3D320/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_6-1707457624852.png" alt="Naveen_n_6-1707457624852.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_7-1707457624855.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63098i42F4477C386BE1E9/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_7-1707457624855.png" alt="Naveen_n_7-1707457624855.png" /></span></P><P><STRONG><SPAN>GET OPERATION: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>METHOD if_rest_resource~get. DATA : ls_so TYPE zna_ty_sales_order, lv_result TYPE string, lv_vbeln TYPE vbeln. DATA : ls_item_condition TYPE zna_ty_sales_ord_item_cond, lt_item_condition TYPE STANDARD TABLE OF zna_ty_sales_ord_item_cond, ls_item TYPE zna_ty_sales_ord_item, lt_item TYPE STANDARD TABLE OF zna_ty_sales_ord_item. "read the uri parameter lv_vbeln = mo_request-&gt;get_uri_query_parameter( iv_name = 'VBELN' * iv_encoded = abap_true ). IF lv_vbeln IS NOT INITIAL. lv_vbeln = |{ lv_vbeln ALPHA = IN }|. . " Select header data select SINGLE * FROM vbak INTO @DATA(ls_vbak) WHERE vbeln = @lv_vbeln. IF ls_vbak-vbeln IS NOT INITIAL. "select line item data SELECT * FROM vbap INTO TABLE @DATA(lt_vbap) WHERE vbeln = @ls_vbak-vbeln. "select conditions SELECT * FROM konv INTO TABLE @DATA(lt_konv) WHERE knumv = @ls_vbak-knumv. "pass the data to structure ls_so-VBELN = ls_vbak-vbeln. ls_so-KUNNR = ls_vbak-kunnr. ls_so-VKORG = ls_vbak-vkorg. ls_so-VTWEG = ls_vbak-vtweg. ls_so-SPART = ls_vbak-spart. ls_so-BSTNK = ls_vbak-bstnk. ls_so-BSTDK = ls_vbak-bstdk. * MESSAGE * ITEMS LOOP AT lt_vbap INTO DATA(ls_vbap). clear ls_item. MOVE-CORRESPONDING ls_vbap TO ls_item. LOOP AT lt_konv INTO DATA(ls_konv) WHERE knumv = ls_vbak-knumv and kposn = ls_vbap-posnr. CLEAR ls_item_condition. ls_item_condition-VBELN = ls_vbap-vbeln. ls_item_condition-POSNR = ls_vbap-posnr. ls_item_condition-KPOSN = ls_konv-kposn. ls_item_condition-stunr = ls_konv-stunr. ls_item_condition-KSCHL = ls_konv-kschl. ls_item_condition-KWERT = ls_konv-kwert. APPEND ls_item_condition TO lt_item_condition. CLEAR ls_konv. ENDLOOP. ls_item-item_condition[] = lt_item_condition[]. APPEND ls_item TO lt_item. CLEAR : ls_vbap,lt_item_condition[]. ENDLOOP. ls_so-items[] = lt_item[]. ELSE. ls_so-message = 'Sales order does not exist'. ENDIF. ELSE. ls_so-message = 'Kindly enter the sales order number'. ENDIF. /ui2/cl_json=&gt;serialize( EXPORTING data = ls_so RECEIVING r_json = lv_result " JSON string ). mo_response-&gt;create_entity( )-&gt;set_string_data( iv_data = lv_result ). mo_response-&gt;set_header_field( EXPORTING iv_name = 'content-Type' " Header Name iv_value = 'application/json' " Header Value ). ENDMETHOD. </code></pre><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_8-1707457624860.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63099iF3C401AC572C86DB/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_8-1707457624860.png" alt="Naveen_n_8-1707457624860.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_9-1707457624863.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63101i2BB9FDC9EA640BF6/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_9-1707457624863.png" alt="Naveen_n_9-1707457624863.png" /></span></P><P><SPAN>Implement the request handler class method “</SPAN><STRONG><SPAN>GET_ROOT_HANDLER</SPAN></STRONG><SPAN>”&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>method IF_REST_APPLICATION~GET_ROOT_HANDLER. DATA(lv_router) = NEW cl_rest_router( ). lv_router-&gt;attach( EXPORTING iv_template = '/zna_so' " Unified Name for Resources iv_handler_class = ' ZCL_NA_REST_RESOURCE_EXT ' " Object Type Name * it_parameter = " Resource contructor parameters ). ro_root_handler = lv_router. endmethod. </code></pre><P>&nbsp;</P><P><SPAN>&nbsp;</SPAN></P><P><SPAN>In T-code:- </SPAN><STRONG><SPAN>SCIF</SPAN></STRONG><SPAN>, we have to create host and test the service.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_10-1707457624865.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63100iEED0951DAAEFA243/image-size/medium?v=v2&amp;px=400" role="button" title="Naveen_n_10-1707457624865.png" alt="Naveen_n_10-1707457624865.png" /></span><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_11-1707457624867.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63102i4D9CCF2B2FCE1666/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_11-1707457624867.png" alt="Naveen_n_11-1707457624867.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_12-1707457624870.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63104i402832AD4CB0668D/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_12-1707457624870.png" alt="Naveen_n_12-1707457624870.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_13-1707457624873.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63105iFE8697196490621B/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_13-1707457624873.png" alt="Naveen_n_13-1707457624873.png" /></span></P><P><SPAN>In this we have to add Handler name and provide sales order number and click on enter.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_14-1707457624874.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63103iADB2DDA402B1D7A7/image-size/medium?v=v2&amp;px=400" role="button" title="Naveen_n_14-1707457624874.png" alt="Naveen_n_14-1707457624874.png" /></span></P><P><SPAN>We have to execute browser and postman tool also.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_0-1707458669292.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63123i7861DF02784066AA/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_0-1707458669292.png" alt="Naveen_n_0-1707458669292.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_2-1707459200565.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63128i615A9FC33A7A23AF/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_2-1707459200565.png" alt="Naveen_n_2-1707459200565.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_3-1707459266016.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63130i9A6468530E799A46/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_3-1707459266016.png" alt="Naveen_n_3-1707459266016.png" /></span></P><P>&nbsp;</P><P><STRONG><SPAN>CREATE OPERATION(POST): -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Here we are inserting the data into the sales order database table.</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>method IF_REST_RESOURCE~POST. DATA : lv_string1 type VBELN, "string, lv_string2 type string, lv_response TYPE string, ls_so TYPE zna_t_so. DATA(lv_entity) = mo_request-&gt;get_entity( ). DATA(lv_responce1) = mo_response-&gt;create_entity( ). *Read string data i.e json DATA(lv_json) = lv_entity-&gt;get_string_data( ). /ui2/cl_json=&gt;deserialize( EXPORTING json = lv_json " JSON string CHANGING data = ls_so " Data to serialize ). INSERT INTO zna_t_so VALUES ls_so. /ui2/cl_json=&gt;serialize( EXPORTING data = ls_so " Data to serialize RECEIVING r_json = lv_response " JSON string ). lv_responce1-&gt;set_string_data( iv_data = lv_response ). endmethod. </code></pre><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_18-1707457624880.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63109i25D37CAFFC805B87/image-size/medium?v=v2&amp;px=400" role="button" title="Naveen_n_18-1707457624880.png" alt="Naveen_n_18-1707457624880.png" /></span></P><P><SPAN>Before doing post operation we can get</SPAN><STRONG><SPAN> csrf token</SPAN></STRONG><SPAN> from the postman tool and after getting token we can pass to value tab.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_4-1707459360387.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63131i53E3771CD800CE01/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_4-1707459360387.png" alt="Naveen_n_4-1707459360387.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_5-1707459425009.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63133i41335A7C580121F0/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_5-1707459425009.png" alt="Naveen_n_5-1707459425009.png" /></span></P><P>&nbsp;</P><P><SPAN>In body section, we need to pass the record and click on send.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_6-1707459590818.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63135iDCB31D32158A9EE3/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_6-1707459590818.png" alt="Naveen_n_6-1707459590818.png" /></span></P><P>&nbsp;</P><P><SPAN>Here we get success code 200 output data will be successfully inserted.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_7-1707459615766.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63136i8F8DD81F8678F466/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_7-1707459615766.png" alt="Naveen_n_7-1707459615766.png" /></span></P><P>&nbsp;</P><P><SPAN>Data will be inserted .</SPAN><SPAN>&nbsp;<BR /></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_8-1707459687864.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63137i9948BC07B91DF510/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_8-1707459687864.png" alt="Naveen_n_8-1707459687864.png" /></span></P><P>&nbsp;</P><P><STRONG><SPAN>UPDATE OPERATION(PUT): -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>method IF_REST_RESOURCE~PUT. DATA : lv_string1 type VBELN, "string, lv_string2 type string, lv_response TYPE string, ls_so TYPE zna_t_so. DATA(lv_entity) = mo_request-&gt;get_entity( ). DATA(lv_responce1) = mo_response-&gt;create_entity( * iv_multipart = abap_false ). *Read string data i.e json DATA(lv_data) = lv_entity-&gt;get_string_data( ). /ui2/cl_json=&gt;deserialize( EXPORTING json = lv_data " JSON string CHANGING data = ls_so " Data to serialize ). UPDATE ZNA_T_SO FROM ls_so. /ui2/cl_json=&gt;serialize( EXPORTING data = ls_so " Data to serialize RECEIVING r_json = lv_response " JSON string ). lv_responce1-&gt;set_string_data( iv_data = lv_response ). endmethod. </code></pre><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_24-1707457624885.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63115iC5B5F5720A05D667/image-size/medium?v=v2&amp;px=400" role="button" title="Naveen_n_24-1707457624885.png" alt="Naveen_n_24-1707457624885.png" /></span></P><P><SPAN>We can change the field value and click on send.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_9-1707459753787.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63139i1373807914E4B641/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_9-1707459753787.png" alt="Naveen_n_9-1707459753787.png" /></span></P><P>&nbsp;</P><P><STRONG><SPAN>BEFORE: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_26-1707457624887.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63117i114947F999D0CDAF/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_26-1707457624887.png" alt="Naveen_n_26-1707457624887.png" /></span></P><P><STRONG><SPAN>AFTER: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_27-1707457624889.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63119iCF9D379F7D4F27EF/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_27-1707457624889.png" alt="Naveen_n_27-1707457624889.png" /></span></P><P><STRONG><SPAN>DELETE OPERATION: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>METHOD if_rest_resource~delete. DATA : lv_string1 TYPE vbeln, "string, lv_string2 TYPE string, lv_response TYPE string, ls_so TYPE zna_t_so. DATA(lv_entity) = mo_request-&gt;get_entity( ). DATA(lv_responce1) = mo_response-&gt;create_entity( * iv_multipart = abap_false ). *Read string data i.e json DATA(lv_data) = lv_entity-&gt;get_string_data( ). /ui2/cl_json=&gt;deserialize( EXPORTING json = lv_data " JSON string CHANGING data = ls_so " Data to serialize ). DELETE zna_t_so FROM ls_so. /ui2/cl_json=&gt;serialize( EXPORTING data = ls_so " Data to serialize RECEIVING r_json = lv_response " JSON string ). lv_responce1-&gt;set_string_data( iv_data = lv_response ). ENDMETHOD. </code></pre><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_28-1707457624890.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63118iC03484449DEF3972/image-size/medium?v=v2&amp;px=400" role="button" title="Naveen_n_28-1707457624890.png" alt="Naveen_n_28-1707457624890.png" /></span><SPAN>&nbsp;</SPAN></P><P><SPAN>Here we delete the value 00000000003.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_11-1707459967794.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63144i06B05CB9ADD49F88/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_11-1707459967794.png" alt="Naveen_n_11-1707459967794.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P><STRONG><SPAN>BEFORE DELETE: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_30-1707457624892.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63121i75811FB769A5C44F/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_30-1707457624892.png" alt="Naveen_n_30-1707457624892.png" /></span></P><P><STRONG><SPAN>AFTER DELETE: -</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Naveen_n_31-1707457624893.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/63122iD5FDDE0F4DD437A3/image-size/large?v=v2&amp;px=999" role="button" title="Naveen_n_31-1707457624893.png" alt="Naveen_n_31-1707457624893.png" /></span></P><P>&nbsp;</P> 2024-02-13T09:02:35.581000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-create-a-value-help-for-custom-and-released-domain-fixed-values/ba-p/13605706 How to create a value help for custom and released domain fixed values? 2024-02-15T02:15:22.925000+01:00 Andre_Fischer https://community.sap.com/t5/user/viewprofilepage/user-id/55 <H2 id="toc-hId-986153060">Introduction</H2><P>For creating value helps based on domain fixed values in ABAP Cloud the recommendation so far was to create custom CDS views based on the released CDS views&nbsp;DDCDS_CUSTOMER_DOMAIN_VALUE&nbsp; and&nbsp;DDCDS_CUSTOMER_DOMAIN_VALUE_T.&nbsp;</P><P>The drawback of this solution is&nbsp;</P><OL><LI>that you have to create dedicated CDS views for each domain and</LI><LI><SPAN>that the aforementioned CDS views only work for domains that reside in software components owned by customers.&nbsp;</SPAN></LI></OL><P>Based on a question in a forum of the German SAP user group DSAG where the question was raised whether there is no alternative solution I thought again about this requirement.&nbsp;</P><P>Instead of using CDS views it is possible just use one single custom entity which uses RTTI to retrieve the domain fixed values.</P><H2 id="toc-hId-789639555">Result</H2><P>When adding the new value help to the projection view as follows:</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> @Consumption.valueHelpDefinition: [{ entity: { name : 'ZI_DOMAIN_FIX_VAL' , element: 'low' } , additionalBinding: [{ element: 'domain_name', localConstant: 'BEL_API_RETCODE', usage: #FILTER }] , distinctValues: true }] Low,</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>We get the following result:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="domain_fix_value_help_result.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/71872iE19ADCE47313411E/image-size/large?v=v2&amp;px=999" role="button" title="domain_fix_value_help_result.png" alt="domain_fix_value_help_result.png" /></span></P><H2 id="toc-hId-593126050">Implementation</H2><P>The challenge to get this to work with just one custom entity is, to provide the name of the domain that is used as a value help via additional binding.&nbsp;</P><P>This can be achieved by using <STRONG>localConstant</STRONG> key word&nbsp;<SPAN>&nbsp;and in addition it needs the <STRONG>usage</STRONG> parameter set to <STRONG>#FILTER</STRONG>. This way we can specify the name of the domain whose domain fixed values shall be used within the coding.</SPAN></P><P><SPAN>Be careful !</SPAN></P><P><SPAN>It doesn't work if the element ("domain_name" in this case) is hidden in the Value Help CDS View (e.g. through "UI.hidden: true").</SPAN></P><H3 id="toc-hId-525695264">Custom Entity</H3><P>The DDL source code of the custom entity looks like this:</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Get domain fix values' @ObjectModel.resultSet.sizeCategory: #XS @ObjectModel.query.implementedBy: 'ABAP:ZCL_GET_DOMAIN_FIX_VALUES' define custom entity ZI_DOMAIN_FIX_VAL { @EndUserText.label : 'domain name' @UI.hidden : true key domain_name : sxco_ad_object_name; @UI.hidden : true key pos : abap.numc( 4 ); @EndUserText.label : 'lower_limit' low : abap.char( 10 ); @EndUserText.label : 'upper_limit' high : abap.char(10); @EndUserText.label : 'Description' description : abap.char(60); }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><H3 id="toc-hId-329181759">Query implementation class</H3><P>And the code of the query implementation class is as follows:</P><P>The domain name is retrieved from the filter that is filled via the additional binding.</P><P>Once the domain name has been retrieved the domain fixed values are being retrieved using RTTI&nbsp;as described in the following blog post&nbsp;<A href="https://community.sap.com/t5/technology-blogs-by-members/fetching-texts-for-domain-fixed-values/ba-p/13578443" target="_blank">Fetching texts for domain fixed values - SAP Community</A>&nbsp;by&nbsp;<A href="https://community.sap.com/t5/user/viewprofilepage/user-id/8484" target="_self">Michał Badura</A>.</P><P>Another option would be to use the XCO library.&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS zcl_get_domain_fix_values DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_rap_query_provider. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_get_domain_fix_values IMPLEMENTATION. METHOD if_rap_query_provider~select. DATA business_data TYPE TABLE OF zi_domain_fix_val . DATA business_data_line TYPE zi_domain_fix_val . DATA(top) = io_request-&gt;get_paging( )-&gt;get_page_size( ). DATA(skip) = io_request-&gt;get_paging( )-&gt;get_offset( ). DATA(requested_fields) = io_request-&gt;get_requested_elements( ). DATA(sort_order) = io_request-&gt;get_sort_elements( ). DATA domain_name TYPE sxco_ad_object_name . DATA pos TYPE i. TRY. DATA(filter_condition_string) = io_request-&gt;get_filter( )-&gt;get_as_sql_string( ). DATA(filter_condition_ranges) = io_request-&gt;get_filter( )-&gt;get_as_ranges( ). READ TABLE filter_condition_ranges WITH KEY name = 'DOMAIN_NAME' INTO DATA(filter_condition_domain_name). IF filter_condition_domain_name IS NOT INITIAL. domain_name = filter_condition_domain_name-range[ 1 ]-low. ELSE. "do some exception handling io_response-&gt;set_total_number_of_records( lines( business_data ) ). io_response-&gt;set_data( business_data ). EXIT. ENDIF. business_data_line-domain_name = domain_name . CAST cl_abap_elemdescr( cl_abap_typedescr=&gt;describe_by_name( domain_name ) )-&gt;get_ddic_fixed_values( EXPORTING p_langu = sy-langu RECEIVING p_fixed_values = DATA(fixed_values) EXCEPTIONS not_found = 1 no_ddic_type = 2 OTHERS = 3 ). IF sy-subrc &gt; 0. "do some exception handling io_response-&gt;set_total_number_of_records( lines( business_data ) ). io_response-&gt;set_data( business_data ). EXIT. ENDIF. LOOP AT fixed_values INTO DATA(fixed_value). pos += 1. business_data_line-pos = pos. business_data_line-low = fixed_value-low . business_data_line-high = fixed_value-high. business_data_line-description = fixed_value-ddtext. APPEND business_data_line TO business_data. ENDLOOP. IF top IS NOT INITIAL. DATA(max_index) = top + skip. ELSE. max_index = 0. ENDIF. SELECT * FROM business_data AS data_source_fields WHERE (filter_condition_string) INTO TABLE business_data UP TO max_index ROWS. IF skip IS NOT INITIAL. DELETE business_data TO skip. ENDIF. io_response-&gt;set_total_number_of_records( lines( business_data ) ). io_response-&gt;set_data( business_data ). CATCH cx_root INTO DATA(exception). DATA(exception_message) = cl_message_helper=&gt;get_latest_t100_exception( exception )-&gt;if_message~get_longtext( ). DATA(exception_t100_key) = cl_message_helper=&gt;get_latest_t100_exception( exception )-&gt;t100key. "do some exception handling ENDTRY. ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2024-02-15T02:15:22.925000+01:00 https://community.sap.com/t5/enterprise-resource-planning-blogs-by-members/creating-tree-tables-with-odata-v4-on-sap-btp-abap-environment/ba-p/13605160 Creating tree tables with OData V4 on SAP BTP ABAP Environment 2024-02-15T09:48:04.555000+01:00 ReinertM https://community.sap.com/t5/user/viewprofilepage/user-id/175444 <P>Since end of last year, it is possible to implement hierarchies in SAP BTP ABAP Environment. Since this feature is fairly easy to implement, here is an end-to-end guide on how to create tree tables on ABAP Environment.&nbsp;<BR /><BR /><STRONG>Step 1:</STRONG> Create a ABAP Package with a name of your choice</P><P><STRONG>Step 2:</STRONG> Create a database table</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Employee Data' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zmriemployee { key employee_id : abap.char(20) not null; first_name : abap.sstring(255); last_name : abap.sstring(255); salary : abap.dec(8,2); salary_currency : abap.cuky; manager : abap.char(20); }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Step 3:</STRONG> Create ABAP Class and fill table with demo data<BR />Note:&nbsp;make sure to add the if_oo_adt_classrun interface to you class to be able to execute the class.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS z_fill_employee_data DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun . DATA: lt_employees TYPE TABLE OF zmriemployee. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS z_fill_employee_data IMPLEMENTATION. METHOD if_oo_adt_classrun~main. APPEND VALUE #( employee_id = '00000001' first_name = 'John' last_name = 'Travolta' salary = '100000.99' salary_currency = 'CHF' ) TO lt_employees. APPEND VALUE #( employee_id = '00000002' first_name = 'Will' last_name = 'Smith' salary = '80000.99' salary_currency = 'USD' manager = '00000001' ) TO lt_employees. APPEND VALUE #( employee_id = '00000003' first_name = 'Jessica' last_name = 'Alba' salary = '85000.99' salary_currency = 'CHF' manager = '00000002' ) TO lt_employees. APPEND VALUE #( employee_id = '00000004' first_name = 'Monica' last_name = 'Belucci' salary = '45987.99' salary_currency = 'EUR' manager = '00000002' ) TO lt_employees. APPEND VALUE #( employee_id = '00000005' first_name = 'Jack' last_name = 'Nicolson' salary = '80000.99' salary_currency = 'CHF' manager = '00000002' ) TO lt_employees. APPEND VALUE #( employee_id = '00000006' first_name = 'Cameron' last_name = 'Diaz' salary = '47856.99' salary_currency = 'USD' manager = '00000005' ) TO lt_employees. out-&gt;write( name = `Employee data to be inserted:` data = lt_employees ). DELETE FROM zmriemployee. INSERT zmriemployee FROM TABLE @lt_employees. COMMIT WORK. CLEAR lt_employees. out-&gt;write( `Insert successful ` ). ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>The table data should look like this:&nbsp;</P><P><U><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ReinertM_0-1707920321841.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/65293iEC63B4A1F2BCD32E/image-size/medium?v=v2&amp;px=400" role="button" title="ReinertM_0-1707920321841.png" alt="ReinertM_0-1707920321841.png" /></span></STRONG></U></P><P>Note: there is a relationship between the employee_id and the manager field. Where the field manager is empty (i.e. inital), we have no allocation to another employee, hence this person is the highest ranked employee.&nbsp;</P><P><STRONG>Step 4:</STRONG>&nbsp;Create view entity as interface view for employee data<BR />When creating the data definition, choose the view entity template and import all fileds into the view (CTRL + SPACE) and implement the many to one association to the database table</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Interface view for employee demo data' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } @Metadata.allowExtensions: true define view entity Z_I_EMPLOYEE_DATA as select from zmriemployee association of many to one Z_I_EMPLOYEE_DATA as _Manager on $projection.Manager = _Manager.EmployeeId { key employee_id as EmployeeId, first_name as FirstName, last_name as LastName, salary as Salary, salary_currency as SalaryCurrency, manager as Manager, _Manager }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Step 5:</STRONG> Define Hierarchy mapping<BR />When creating the data definition, choose the Define Parent Child Hierarchy Template and define the hierarchy relationship.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Hierarchy: Read Only: Employee Hierarchy' define hierarchy Z_I_EMPLOYEE_DATA_HN as parent child hierarchy( source Z_I_EMPLOYEE_DATA child to parent association _Manager start where Manager is initial siblings order by LastName ascending ) { key EmployeeId, Manager }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Step 6:</STRONG> Create consumption view (data definition) with reference to the hierarchy entity.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Hierarchy: Read Only: Employee' @Metadata.allowExtensions: true @Search.searchable: true @OData.hierarchy.recursiveHierarchy:[{ entity.name: 'Z_I_EMPLOYEE_DATA_HN' }] define view entity Z_C_EMPLOYEE_DATA as select from Z_I_EMPLOYEE_DATA association of many to one Z_C_EMPLOYEE_DATA as _Manager on $projection.Manager = _Manager.EmployeeId { key EmployeeId, @Search: { defaultSearchElement: true} FirstName, LastName, Salary, SalaryCurrency, Manager, /* Associations */ _Manager }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Step 7:</STRONG>&nbsp;Create Metadata Extension with UI5 annotations.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE @UI: { headerInfo: { typeName: 'Employee', typeNamePlural: 'Employees', title: { type: #STANDARD, value: 'EmployeeId' } }, presentationVariant: [{ sortOrder: [{ by: 'EmployeeId', direction: #ASC }], visualizations: [{type: #AS_LINEITEM}] }] } annotate entity Z_C_EMPLOYEE_DATA with { @UI: { facet: [ { id: 'EmployeeId', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'EmployeeId', position: 10 } ] } @UI: { lineItem: [{ position: 20 , label: 'The emoloyee id'}], identification: [{ position: 20 }] } EmployeeId; @UI: { selectionField: [{ position: 30 }], lineItem: [{ position: 30 }], identification: [{ position: 30 }] } FirstName; @UI: { selectionField: [{ position: 30 }], lineItem: [{ position: 40 }], identification: [{ position: 40 }] } LastName; @UI: { lineItem: [{ position: 50 }], identification: [{ position: 50 }] } Salary; @UI: { lineItem: [{ position: 70 }], identification: [{ position: 70 }] } Manager; }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Step 8:</STRONG> Create Service Definition to expose the consumption view.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Service Defintion' @ObjectModel.leadingEntity.name: 'Z_C_EMPLOYEE_DATA' define service Z_UI_Employee_DATA { expose Z_C_EMPLOYEE_DATA as Employee; }</code></pre><P>&nbsp;</P><P><STRONG>Step 9:</STRONG> Create Service Binding of Binding Type "OData V4 UI" and publish service binding.</P><P><U><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ReinertM_2-1707919091052.jpeg" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/65282i38FD5390011C0FB3/image-size/medium?v=v2&amp;px=400" role="button" title="ReinertM_2-1707919091052.jpeg" alt="ReinertM_2-1707919091052.jpeg" /></span></U></P><P><STRONG>Step 10:</STRONG> Click on the preview button and voilà: the table is rendered with a tree structure.</P><P><U><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ReinertM_1-1707918954297.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/65281i30DAFF34203D0FB3/image-size/medium?v=v2&amp;px=400" role="button" title="ReinertM_1-1707918954297.png" alt="ReinertM_1-1707918954297.png" /></span></U></P><P><U>Note:</U> It is important to comply with the data type and strucure of the node_id which is the central component for rendering the tree structure. If you are running into an error when calling your Fiori Fontend, use the Ecplise Debugger to trace down the error. Most likely it is because the field which is used for the hierarchy association does not match the expected data type and you will run into an ABAP Runtime error (e.g. RAISE_SHORTDUMP) or a HTTP error ($batch failed).</P><P>&nbsp;</P> 2024-02-15T09:48:04.555000+01:00 https://community.sap.com/t5/technology-blogs-by-members/dynamically-show-hide-enable-disable-fields-in-fiori-elements/ba-p/13609053 Dynamically show/hide enable/disable fields in Fiori Elements 2024-02-19T08:05:02.709000+01:00 Mikhail_Minakov https://community.sap.com/t5/user/viewprofilepage/user-id/163112 <P>Sometimes you need to hide or disable the field in UI dynamically based on condition, for example based on entered data in edit mode.</P><P>You can make it in backend using&nbsp;hide annotation with value based on control field. Changing the value of control field via value help additional bindings or determination with side effects.</P><P>Use Case: In our app for order creation user is entering order code first. Based on the value of order code the device location field or the device number field should be enabled dynamically in edit mode. I one is enabled for entering the other must be read only.&nbsp;</P><H2 id="toc-hId-986265649">1. Hide annotation based on another field</H2><P>First of all we create two additional read only fields in Interface and projection views</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>devloc as deviceLocation, devloc as deviceLocationRO, ... _Equipment.SerialNumber as deviceNumber, _Equipment.SerialNumber as deviceNumberRO,</code></pre><P>&nbsp;</P><P>&nbsp;</P><DIV><P>Then we make read only fields read only in behaviour definition</P></DIV><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>field ( readonly ) deviceNumberRO, deviceLocationRO;</code></pre><P>&nbsp;</P><P>The idea is to hide the editable field showing the readonly field what makes user thinking the field is disabled/enabled dynamically.</P><P>So we add another four control fields, which will contain true or false based on condition, and will be used as value for hide annotation</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>_OrderCode.hideDevLoc as hideDevLocation, _OrderCode.hideSerNum as hideDevNumber, _OrderCode.hideDevLocRO as hideDevLocationRO, _OrderCode.hideSerNumRO as hideDevNumberRO,</code></pre><P>&nbsp;</P><P>We need four of them to be able to hide all of fields until user enters order code.</P><P>Now we bind all this together, making aur fields be hideable depending of the value of control fields. I am using annotation.xml in UI, but the same can be done in backend metadata extension.</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>&lt;Record Type="UI.DataField"&gt; &lt;PropertyValue Property="Value" Path="deviceNumber"/&gt; &lt;Annotation Term="UI.Hidden" Path="hideDeviceNumber" /&gt; &lt;/Record&gt; &lt;Record Type="UI.DataField"&gt; &lt;PropertyValue Property="Value" Path="deviceNumberRO"/&gt; &lt;Annotation Term="UI.Hidden" Path="hideDevNumberRO" /&gt; &lt;/Record&gt; ... &lt;Record Type="UI.DataField"&gt; &lt;PropertyValue Property="Value" Path="deviceLocationRO"/&gt; &lt;Annotation Term="UI.Hidden" Path="hideDevLocationRO" /&gt; &lt;/Record&gt; &lt;Record Type="UI.DataField"&gt; &lt;PropertyValue Property="Value" Path="deviceLocation"/&gt; &lt;Annotation Term="UI.Hidden" Path="hideDevLocation"/&gt; &lt;/Record&gt; ...</code></pre><P>&nbsp;</P><P>In the same way for deviceLocation and deviceLocationRO.</P><P>The next step here is to set the values of control fields as additional binding of order code value help view ZI_DM_CSORDER_OCODE_VH:</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>define view ZI_DM_CSORDER_OCODE_VH as select from ... { ... @UI.hidden: true cast(case when bzgsobjtyp='01' then 'X' else '' end as boolean) as hideSerNum, @UI.hidden: true cast(case when bzgsobjtyp='03' then 'X' else '' end as boolean) as hideDevLoc, @UI.hidden: true cast(case when bzgsobjtyp='01' then '' else 'X' end as boolean) as hideSerNumRO, @UI.hidden: true cast(case when bzgsobjtyp='03' then '' else 'X' end as boolean) as hideDevLocRO, ... }</code></pre><P>&nbsp;</P><P>Value Help for order code is defined as following:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Consumption.valueHelpDefinition: [ { entity : {name: 'ZI_DM_CSORDER_OCODE_VH', element: 'orderCode'}, { localElement: 'hideDevLocation', element: 'hideDevLoc', usage: #RESULT }, { localElement: 'hideDevNumber', element: 'hideSerNum', usage: #RESULT }, { localElement: 'hideDevLocationRO', element: 'hideDevLocRO', usage: #RESULT }, { localElement: 'hideDevNumberRO', element: 'hideSerNumRO', usage: #RESULT } ] orderCode,</code></pre><P>&nbsp;</P><P>As of now, when user changed order code, the control fields hideDevice* will be updated with the values generated in value help view causing dynamically hiding of fields in edit mode. The same behaviour may be achieved with determination code and side effects.</P><P>How it looks in UI.&nbsp;</P><P>Case 1 - user enters order code for device location. Device location is showing, device number is hided.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Mikhail_Minakov_0-1708259092917.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/67162iB44D6AC639A0979A/image-size/medium?v=v2&amp;px=400" role="button" title="Mikhail_Minakov_0-1708259092917.png" alt="Mikhail_Minakov_0-1708259092917.png" /></span></P><P>Case 2 - user enters order code for device number. Device number is showing for edit, device location is showing read only, because it will be determined later based on device number data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Mikhail_Minakov_1-1708259236578.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/67163iD36302E9592500D5/image-size/medium?v=v2&amp;px=400" role="button" title="Mikhail_Minakov_1-1708259236578.png" alt="Mikhail_Minakov_1-1708259236578.png" /></span></P> 2024-02-19T08:05:02.709000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/cds-based-bopf-to-rap-migration-tool/ba-p/13588579 CDS-based BOPF to RAP Migration Tool 2024-02-20T09:28:33.171000+01:00 SteffenMattes https://community.sap.com/t5/user/viewprofilepage/user-id/357433 <H1 id="toc-hId-835917029">CDS-based BOPF to RAP Migration Tool</H1><P><SPAN>Have you built CDS-based BOPF business objects using the </SPAN><A href="https://help.sap.com/docs/ABAP_PLATFORM_NEW/cc0c305d2fab47bd808adcad3ca7ee9d/3b77569ca8ee4226bdab4fcebd6f6ea6.html?locale=en-US" target="_blank" rel="noopener noreferrer">ABAP Programming Model for SAP Fiori</A>&nbsp;<SPAN>and ever wondered whether and how they can be integrated into </SPAN><A href="https://help.sap.com/docs/abap-cloud/abap-rap/abap-restful-application-programming-model?locale=en-US" target="_blank" rel="noopener noreferrer">ABAP RESTful Application Programming Model (RAP)</A><EM>?&nbsp;</EM></P><P>With <EM>SAP S/4HANA 2023</EM> and <EM>SAP S/4HANA Cloud Private <FONT color="#000000">E</FONT>dition 2023</EM>, the long-awaited migration tool is now available for pilot customers.</P><P><SPAN>Follow the instructions provided in SAP Note </SPAN><A href="https://help.sap.com/docs/link-disclaimer?site=https://me.sap.com/notes/3392337" target="_blank" rel="noopener noreferrer">3392337</A><SPAN> to enable the tool for your system.</SPAN></P><H3 id="toc-hId-897568962"><FONT color="#000000">Upgrade your existing CDS-based BOPF BOs</FONT></H3><P>But why should you migrate your existing business objects (BOs) based on Core Data Service (CDS) and the Business Object Processing Framework (BOPF) to RAP?</P><P><SPAN>RAP is an essential element of <A href="https://blogs.sap.com/2023/05/26/abap-cloud-sap-s-4hana-extensibility-may-2023-update/" target="_self" rel="noopener noreferrer">ABAP Cloud</A> and offers great new concepts and features to enhance and interact with RAP business objects:</SPAN></P><UL><LI><SPAN>Interact programmatically with RAP BOs using the&nbsp;Entity Manipulation Language (EML),</SPAN></LI><LI><SPAN>easily expose RAP BOs as OData V2 or V4 services for Integration Services or SAP Fiori,</SPAN></LI><LI><SPAN>define and raise RAP Business Events, </SPAN></LI><LI><SPAN>use or enable developer extensibility for modification-free enhancements,</SPAN></LI><LI><SPAN>apply the same standard development model as used in SAP S/4HANA.&nbsp;</SPAN></LI></UL><P><SPAN>You can benefit from these capabilities and enhance your business object with new RAP features while reusing your implemented&nbsp;</SPAN><SPAN>business logic. Your existing OData service and Fiori application can continue to be used as well. Nevertheless, adapting to the RAP standard by modernizing your service exposure to service definition and service binding is a worthwhile investment.</SPAN></P><H3 id="toc-hId-701055457">CDS-based BOPF to RAP Migration&nbsp;and&nbsp;ABAP Cloud</H3><P><SPAN>A migration of </SPAN><SPAN>your CDS-based BOPF BO opens the possibility to enable your BO for consumption in the </SPAN><SPAN><A href="https://www.sap.com/documents/2023/05/b0bd8ae6-747e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">3-Tier Extensibility Model of ABAP Cloud</A></SPAN><SPAN>:&nbsp;</SPAN><SPAN>A new RAP BO Interface with release contract&nbsp;<EM>Use System-Internally ( Contract C1 )</EM>&nbsp;and visibility <EM>Use in Cloud Development</EM>&nbsp;can be defined for the migrated BO.&nbsp;</SPAN><SPAN>The BOPF BO remains in Tier 3 and therefore is not part of ABAP Cloud. </SPAN><SPAN><SPAN>However, t</SPAN><SPAN>he business logic can now be consumed in ABAP Cloud via the released RAP BO interface.</SPAN></SPAN></P><H3 id="toc-hId-504541952">The Migration Tool</H3><P><SPAN>The migration tool </SPAN><SPAN>is integrated into ADT and can be easily accessed by right-clicking on your BOPF BO in the Project Explorer and then selecting&nbsp;<EM>RAP Business Object &gt; Migrate</EM>.</SPAN><SPAN>&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MartinBretzer_0-1707408036950.png" style="width: 534px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/62906i95672FF616F22593/image-dimensions/534x403?v=v2" width="534" height="403" role="button" title="MartinBretzer_0-1707408036950.png" alt="MartinBretzer_0-1707408036950.png" /></span></P><P><SPAN>The tool provides two different modes:</SPAN></P><UL><LI><SPAN>A simulation mode for documenting results in a log without making any changes,</SPAN></LI><LI><SPAN>a migration mode for&nbsp;migrating the artifacts in the system.</SPAN></LI></UL><P>In both cases, the tool analyzes your CDS-based BOPF BO and underlying CDS views and provides information on the necessary pre- or post-processing steps required for a successful migration to RAP.</P><P><!-- StartFragment --><SPAN class="">The migration tool provides a lot of support and automated steps for the migration process. Nevertheless, the migration of a CDS-based BOPF BO to a RAP BO can be a complex task. Therefore please make sure to consider the messages provided by the tool, as well as the constraints documented in the migration guide.</SPAN><!-- EndFragment --></P><P><SPAN>Check out the </SPAN><SPAN><A href="https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/0a54d0c8a2be4136a8b5d41a367dd537/2e48e205756c4dafb02ef0e2ff14b1bc.html?locale=en-US" target="_blank" rel="noopener noreferrer">Migration Guide</A></SPAN><SPAN> in the SAP help portal to start your migration journey </SPAN><SPAN><span class="lia-unicode-emoji" title=":smiling_face_with_smiling_eyes:">😊</span></SPAN><SPAN>&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><H3 id="toc-hId-308028447"><SPAN>Useful Links</SPAN></H3><P><SPAN><A href="https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/0a54d0c8a2be4136a8b5d41a367dd537/2e48e205756c4dafb02ef0e2ff14b1bc.html?locale=en-US" target="_blank" rel="noopener noreferrer">Migration Guide</A></SPAN></P><P><SPAN><A href="https://help.sap.com/docs/abap-cloud/abap-rap/abap-restful-application-programming-model?locale=en-US" target="_blank" rel="noopener noreferrer">RAP Online Documentation</A></SPAN></P><P><A href="https://help.sap.com/docs/abap-cloud/abap-cloud/why-abap-cloud" target="_self" rel="noopener noreferrer">ABAP Cloud: Background Concepts and Overview</A></P><P><SPAN><A href="https://www.sap.com/documents/2023/05/b0bd8ae6-747e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">3 Tier Extensibility Model</A></SPAN></P><P><SPAN><A href="https://help.sap.com/docs/ABAP_PLATFORM_NEW/cc0c305d2fab47bd808adcad3ca7ee9d/3b77569ca8ee4226bdab4fcebd6f6ea6.html?locale=en-US" target="_blank" rel="noopener noreferrer">SAP Programming Model for SAP Fiori</A></SPAN></P> 2024-02-20T09:28:33.171000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-reuse-access-control-from-a-released-sap-cds-entity-in-abap-cloud/ba-p/13622564 How to reuse access control from a released SAP CDS entity in ABAP Cloud? 2024-02-28T15:14:56.649000+01:00 Andre_Fischer https://community.sap.com/t5/user/viewprofilepage/user-id/55 <H2 id="toc-hId-987908991">Introduction</H2><P>When you want to reuse the access control settings from a released SAP CDS entity such as&nbsp;<SPAN>I_BUSINESSUSERBASIC in ABAP Cloud (e.g in SAP BTP ABAP Environment or in a software component in an SAP S/4HANA on prem or private cloud system that uses software components with ABAP Cloud) you might try the following DCL source code:</SPAN></P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Test DCL inheritence' @MappingRole: true define role ZI_BUSINESSUSERBASIC_NOTWORK { grant select on ZI_BUSINESSUSERBASIC where INHERITING CONDITIONS FROM ENTITY I_BUSINESSUSERBASIC; }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P><SPAN>This however would cause the following error message:</SPAN></P><P><STRONG><EM>The use of inheritance is restricted in this language version</EM></STRONG></P><P>The reason is that the reuse of access control requires a special syntax.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="the use of 2.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/72770i81C9FB1007946DF2/image-size/large?v=v2&amp;px=999" role="button" title="the use of 2.png" alt="the use of 2.png" /></span></P><H1 id="toc-hId-662312767">&nbsp;</H1><H1 id="toc-hId-465799262">Solution</H1><P>In order to reuse the access controll settings of a base entity that has been released by SAP you have to equip your custom code entity with a [1..1] association <STRONG>_toBaseEntity</STRONG> that points back to the base entity.</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #MANDATORY @EndUserText.label: 'test dcl inheritence' define view entity ZI_BusinessUserBasic as select from I_BusinessUserBasic association [1..1] to I_BusinessUserBasic as _toBaseEntity on $projection.BusinessPartner = _toBaseEntity.BusinessPartner { key BusinessPartner, BusinessPartnerUUID, LastName, FirstName, PersonFullName, FormOfAddress, AcademicTitle, AcademicSecondTitle, CorrespondenceLanguage, MiddleName, AdditionalLastName, BirthName, NickName, Initials, LastNamePrefix, LastNameSecondPrefix, NameSupplement, UserID, IsMarkedForArchiving, BusinessPartnerIsBlocked, CreatedByUser, CreationDate, CreationTime, LastChangedByUser, LastChangeDate, LastChangeTime, IsBusinessPurposeCompleted, AuthorizationGroup, DataControllerSet, DataController1, DataController2, DataController3, DataController4, DataController5, DataController6, DataController7, DataController8, DataController9, DataController10, /* Associations */ _BusinessPartnerExternalID, _BusinessPartnerRole, _User, _WorkplaceAddress, _toBaseEntity }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>In addition you have to use the following syntax in your DCL.</P><P>The statement&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>REPLACING { ROOT WITH _toBaseEntity }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>makes sure that inheritence will still work even if SAP would add additional authorization checks in the where clause of the DCL that protects the released base entity I_BusinessUserBasic.</P><P>Though the syntax seems to be not self explaining at a first glance it is straight forward to simply create the above mentioned [1..1] association to the based entity.</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Test DCL inheritence' @MappingRole: true define role ZACL_ZI_BUSINESSUSERBASIC { grant select on ZI_BUSINESSUSERBASIC where INHERITING CONDITIONS FROM ENTITY I_BUSINESSUSERBASIC REPLACING { ROOT WITH _toBaseEntity } // AND ... to make it more restricive // OR .... to widen access for additional autorizations ; }</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>Hope this helps when you run into this issue.&nbsp; &nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2024-02-28T15:14:56.649000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-learning-journey-building-odata-services-with-sap-gateway/ba-p/13623812 SAP Learning Journey – Building OData Services with SAP Gateway 2024-02-29T15:30:09.480000+01:00 StefanFell https://community.sap.com/t5/user/viewprofilepage/user-id/4321 <P>Since it was announced at SAP TechEd 2021, SAP offers digital learnings free of charge to everybody interested in SAP products on <A href="https://learning.sap.com" target="_blank" rel="noopener noreferrer">https://learning.sap.com</A>. In this blog post, I want to present to you the learning journey <A href="https://learning.sap.com/learning-journey/building-odata-services-with-sap-gateway" target="_blank" rel="noopener noreferrer">Building OData Services with SAP Gateway</A> and keep you up to date on the latest additions.</P><P>If you are more interested in a customer course for SAP Gateway, please read my blog post:<BR /><A href="https://community.sap.com/t5/blogs/blogworkflowpage/blog-id/technology-blog-sap/article-id/170557" target="_blank">Customer course GW100 (SAP Gateway – Building OData Services) available for SAP S/4HANA 2021</A><BR /><BR /></P><H3 id="toc-hId-1117024227"><STRONG>Latest Additions</STRONG></H3><P>2023-11 Learning journey available<BR /><BR /></P><H2 id="toc-hId-791428003"><STRONG>Introduction</STRONG></H2><P>This learning journey is based on the customer course <A href="https://training.sap.com/course/GW100" target="_blank" rel="noopener noreferrer">GW100 (SAP Gateway – Building OData Services)</A>. The course structure was reworked to provide a clear path following the learning goals of each unit. Many animations and videos support the digital learning experience inviting you to interact with the material.</P><P>Nearly every lesson provides at least one exercise showing steps in a written form. Some can be performed directly by using some public resource like the <A href="https://community.sap.com/t5/technology-blogs-by-sap/new-sap-gateway-demo-system-available/ba-p/13353480" target="_blank">SAP Gateway Demo System</A>, but most exercises are based on SAP S/4HANA 2021 FPS02. In addition to the written form, these exercises provide a simulation of the steps in an SAP Learning system.</P><P>The units in the current version are the following:</P><OL><LI>SAP Gateway Overview</LI><LI>OData Overview</LI><LI>SAP Gateway and CDS Views<BR /><BR /></LI></OL><H2 id="toc-hId-594914498"><STRONG>Content</STRONG></H2><H3 id="toc-hId-527483712"><STRONG>1. SAP Gateway Overview</STRONG></H3><P>Unit 1 first describes <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/describing-sap-gateway_a26e5530-f09b-4419-a331-5ec1b0a031fd" target="_blank" rel="noopener noreferrer">SAP Gateway</A> in general showing examples of where and how it is used in todays SAP solutions. The second lesson digs deeper in the releases and the components of SAP Gateway culminating in the <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/describing-sap-gateway-deployment-options_fd6c68c5-e698-48cb-8772-9188e982284c" target="_blank" rel="noopener noreferrer">deployment options</A> for on-premise and SAP Business Technology Platform (BTP).</P><P>The following is exercised:</P><UL><LI><A href="https://education.hana.ondemand.com/education/pub/mmcp/index.html?show=project!PR_21105BC84BF0B19A:uebung#2" target="_blank" rel="noopener nofollow noreferrer">Prepare the SAP Learning System</A></LI></UL><H3 id="toc-hId-330970207"><STRONG>2. OData Overview</STRONG></H3><P>Unit 2 covers the OData standard from the perspective of SAP Gateway. A short introduction to <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/explaining-representational-state-transfer-rest-_d2855a5f-d583-496f-b6ef-267308618734" target="_blank" rel="noopener noreferrer">REST</A> is followed by a comprehensive explanation of the <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/explaining-open-data-protocol-odata-_f617c2ae-47ee-451f-9aec-61a99440abe7" target="_blank" rel="noopener noreferrer">OData protocol</A>, how to perform <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/performing-odata-operations_a5b5c828-6206-4091-a74e-cf009bb171e4" target="_blank" rel="noopener noreferrer">OData operations</A> and how to handle <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/performing-odata-queries_ee225809-f372-4580-ad9e-a062e1f7c916" target="_blank" rel="noopener noreferrer">OData queries</A>. &nbsp;</P><P>The following is exercised:</P><UL><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_2851D15943F47A8F:uebung" target="_blank" rel="noopener nofollow noreferrer">Examine an OData Service</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_943CFD1FEF51DAA9:uebung" target="_blank" rel="noopener nofollow noreferrer">Perform OData Operations</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_9150ED20234FA59E:uebung" target="_blank" rel="noopener nofollow noreferrer">Perform OData Queries</A></LI></UL><H3 id="toc-hId-134456702"><STRONG>3. SAP Gateway and CDS Views</STRONG></H3><P>Unit 3 jumps to the world of Core Data Services (CDS) and shows the four ways an SAP Gateway service can be <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/explaining-sap-gateway-services-based-on-cds-views_d2f6bd5c-f5ab-43bd-8538-2edb14470a98" target="_blank" rel="noopener noreferrer">generated based on CDS views</A>. This includes a short excursion to the ABAP RESTful Application Programming Model (RAP) but without getting into the details. The focus is to provide SAP Gateway services first by <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/mapping-cds-views-as-data-source_cff6ac93-0bf7-4ccc-9a54-1c899d0d544b" target="_blank" rel="noopener noreferrer">mapping</A> or <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/referencing-a-data-source_e4a63b0d-3052-482f-884e-4d941042af62" target="_blank" rel="noopener noreferrer">referencing</A> a CDS view as data source in the SAP Gateway Service Builder (SEGW). <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/publishing-cds-views-as-sap-gateway-services_f056a12d-3e0f-483e-9e3e-09643cae7f46" target="_blank" rel="noopener noreferrer">Publishing</A> a CDS view as SAP Gateway service or defining <A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway/defining-business-services_dbe161ff-1b51-4f5f-9971-ade9a0f21cb8" target="_blank" rel="noopener noreferrer">business services</A> are performed in the ABAP Development Tools (ADT).</P><P>The following is exercised:</P><UL><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_30BADA87BCED2B4:uebung" target="_blank" rel="noopener nofollow noreferrer">Create an SAP Gateway Service by Mapping CDS Views – Part 1</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_35635B35C55648AB:uebung" target="_blank" rel="noopener nofollow noreferrer">Create an SAP Gateway Service by Mapping CDS Views – Part 2</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_FA170E13F64432A4:uebung" target="_blank" rel="noopener nofollow noreferrer">Create and SAP Gateway Service by Referencing a Data Source</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_95DEE198F60E78F:uebung" target="_blank" rel="noopener nofollow noreferrer">Implement OData.Publish in a CDS View – Part 1</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_364C21AAFEFDAF85:uebung" target="_blank" rel="noopener nofollow noreferrer">Implement OData.Publish in a CDS View – Part 2</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_402562F5679A1AB3:uebung" target="_blank" rel="noopener nofollow noreferrer">Implement a Navigation Using Associations in CDS Views</A></LI><LI><A href="https://education.hana.ondemand.com/education/wa/mmcp/index.html?show=project!PR_8EC6F389FCF2349E:uebung" target="_blank" rel="noopener nofollow noreferrer">Define a Business Service Definition and Binding</A><BR /><BR /></LI></UL><H2 id="toc-hId--191139522"><STRONG>Summary</STRONG></H2><P>If you have read so far, it seems that you are really thinking about consuming the learning journey. Don’t hesitate and jump right in:</P><P><A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway" target="_blank" rel="noopener noreferrer">https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway</A></P><P>If you are more interested in a customer course for SAP Fiori, please visit <A href="https://training.sap.com" target="_blank" rel="noopener noreferrer">https://training.sap.com</A>. The GW100 (SAP Gateway – Building OData Services) is a 5-day-course offered as physical and virtual event:</P><P><A href="https://training.sap.com/course/GW100" target="_blank" rel="noopener noreferrer">https://training.sap.com/course/GW100</A></P><P>For any other questions around the offerings of SAP Learning Services, please jump to our community page and get in contact with us:</P><P><A href="https://pages.community.sap.com/topics/training-certification" target="_blank" rel="noopener noreferrer">https://pages.community.sap.com/topics/training-certification</A></P><P>Happy learning<BR />Stefan</P> 2024-02-29T15:30:09.480000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/customer-course-gw100-sap-gateway-building-odata-services-available-for-sap/ba-p/13623919 Customer Course GW100 (SAP Gateway – Building OData Services) Available for SAP S/4HANA 2021 2024-02-29T15:33:56.276000+01:00 StefanFell https://community.sap.com/t5/user/viewprofilepage/user-id/4321 <P>Now that I finished the course development of the GW100 (again), I thought it is time to summarize all the new and updated topics in a central place. I decided that a blog post here would be a good way to share this to fellow ABAP developers. So welcome to my first blog post about the customer training <A href="https://training.sap.com/course/GW100" target="_blank" rel="noopener noreferrer">GW100 (SAP Gateway – Building OData Services)</A>.</P><P>If you are more interested in a digital learning for SAP Gateway, please read my blog post:<BR /><A href="https://community.sap.com/t5/blogs/blogworkflowpage/blog-id/technology-blog-sap/article-id/170554" target="_blank">SAP Learning Journey – Building OData Services with SAP Gateway</A><BR /><BR /></P><H2 id="toc-hId-987942476"><STRONG>Introduction</STRONG></H2><P>Starting in 2014, this is now the seventh incarnation of how to develop OData services with SAP Gateway. The course shows all parts of SAP Gateway, which are available since SAP NetWeaver Application Server 7.0 (SAP Gateway 2.0), as well as parts added up to SAP S/4HANA 2021. The whole bandwidth of SAP Gateway covering all releases is shown.</P><P>The units in the current version are the following:</P><OL><LI>SAP Gateway Overview</LI><LI>OData Overview</LI><LI>SAP Gateway Service Implementation</LI><LI>SAP Gateway Service Generation</LI><LI>SAP Gateway Service Redefinition</LI><LI>SAP Gateway and CDS Views</LI><LI>SAP Gateway Hub Functionalities</LI><LI>Advanced OData Options</LI><LI>SAP Gateway Security</LI><LI>Further Information</LI></OL><P>If customers are interested, they can order a <A href="https://training.sap.com/content/CSTEN" target="_blank" rel="noopener noreferrer">customer specific</A> version of the course including only those topics suitable for their release or purpose.<BR /><BR /></P><H2 id="toc-hId-791428971"><STRONG>System Landscape</STRONG></H2><P>Let’s start with the system release: SAP S/4HANA 2021 FPS02. Our system landscape – we call it universal target – is used in many technology courses and offers full access for the participants from the SAP Fiori launchpad (FLP) in the browser down to SAP HANA on the SUSE Linux Enterprise server (SLES). Everything is set up following the newest guidelines of SAP so that it can really act as a template for customers.<span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="GW100 System Landscape (Screenshot from System Setup Guide)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73544i8B80F0D078B6E608/image-size/large?v=v2&amp;px=999" role="button" title="Folie1.PNG" alt="GW100 System Landscape (Screenshot from System Setup Guide)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">GW100 System Landscape (Screenshot from System Setup Guide)</span></span></P><P>In addition, we offer an instance of the SAP Business Application Studio (BAS) to show the consumption of OData services. If you want to know more about this topic, check out our courses for <A href="https://training.sap.com/trainingpath/Database+&amp;+Technology-Development-SAP+Fiori" target="_blank" rel="noopener noreferrer">SAP Fiori development</A>.<BR /><BR /></P><H2 id="toc-hId-594915466"><STRONG>OData</STRONG></H2><P>The unit explaining the OData foundation was greatly increased to cover all aspects of the protocol including OData V4. Many more slides were added to visualize the structure of an OData service. Here is an example about function and action imports:<span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="Function and Action Imports (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73440i81E17C1DCC254BEC/image-size/large?v=v2&amp;px=999" role="button" title="Folie2.PNG" alt="Function and Action Imports (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Function and Action Imports (Screenshot from GW100)</span></span><SPAN>A new section covering <EM>?sap-ds-debug=true</EM> was added to explain the features of this debugging query option. Although it was always part of exercises, there was only one slide showing it. Now the following one is just the first one:</SPAN><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="SAP Debugging Query Option for Any Browser (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73441i509322C564BF3CCF/image-size/large?v=v2&amp;px=999" role="button" title="Folie3.PNG" alt="SAP Debugging Query Option for Any Browser (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">SAP Debugging Query Option for Any Browser (Screenshot from GW100)</span></span><SPAN>The lesson about performing OData requests was enhanced in its visualization and some additional slides were added like this one for batch processing:</SPAN><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="OData Option $batch (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73442i3C09DDD6904F933A/image-size/large?v=v2&amp;px=999" role="button" title="Folie4.PNG" alt="OData Option $batch (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">OData Option $batch (Screenshot from GW100)</span></span></P><H2 id="toc-hId-398401961"><STRONG>Implementation</STRONG></H2><P>The structure of the units covering code-based implementation got refined to better fit the current state of development. This includes more graphical explanations of how the source code is structured in the system like this one:<span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="Data Provider Base Class – Source Code (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73443iF2E7178F95D50793/image-size/large?v=v2&amp;px=999" role="button" title="Folie5.PNG" alt="Data Provider Base Class – Source Code (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Data Provider Base Class – Source Code (Screenshot from GW100)</span></span><SPAN>Other slides were enhanced using semantical colors consistently throughout the material. In this example, you see blue used for ABAP code, gold for HTTP requests, and green for (successful) HTTP responses:</SPAN><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="Create Operation Essentials (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73447i67DE01F6A0AE60F0/image-size/large?v=v2&amp;px=999" role="button" title="Folie6.PNG" alt="Create Operation Essentials (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Create Operation Essentials (Screenshot from GW100)</span></span><SPAN>But of course, at the end of the day, it is all about source code. There are now more code snippets outside of exercises and the code is explained in more detail on slides:</SPAN><EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="Implement Paging (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73543i7BC97F497B451431/image-size/large?v=v2&amp;px=999" role="button" title="Folie7.PNG" alt="Implement Paging (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Implement Paging (Screenshot from GW100)</span></span></EM></P><H2 id="toc-hId-201888456"><STRONG>CDS Views</STRONG></H2><P>The evolution of CDS views was driving SAP Gateway from the beginning. That is why there is an own unit keeping track of all possibilities to generate SAP Gateway services based on CDS views:<EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="OData Service Development with CDS – Comparison (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73450i9FF4AF7B8252A3BE/image-size/large?v=v2&amp;px=999" role="button" title="Folie8.PNG" alt="OData Service Development with CDS – Comparison (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">OData Service Development with CDS – Comparison (Screenshot from GW100)</span></span></EM>The decision, which generator is the right one for your project, does not only depend on the release you are using. Especially in a brown field approach, the data source reference in the SAP Gateway Service Builder (SEGW) is still a viable option for reusing existing source code in SAP Gateway services based on CDS views:<SPAN>&nbsp;</SPAN><EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="How to Reference a Data Source (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73455iEDC6674ABF666C3B/image-size/large?v=v2&amp;px=999" role="button" title="Folie9.PNG" alt="How to Reference a Data Source (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">How to Reference a Data Source (Screenshot from GW100)</span></span></EM>The newest generators are Business Services, which are part of the ABAP RESTful Application Programming Model (RAP). They are recommended by SAP as soon as they are available in your system and include the generation of OData V4 services:<EM><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="How to Create a Service Definition and Binding (Screenshot from GW100)" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/73453i27475A6F26C77DF8/image-size/large?v=v2&amp;px=999" role="button" title="Folie10.PNG" alt="How to Create a Service Definition and Binding (Screenshot from GW100)" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">How to Create a Service Definition and Binding (Screenshot from GW100)</span></span></EM></P><H2 id="toc-hId-5374951"><STRONG>Summary</STRONG></H2><P>If you have read so far, it seems that you are really thinking about attending the course. Don’t hesitate and check out the physical and virtual events we offer:</P><P><A href="https://training.sap.com/course/GW100" target="_blank" rel="noopener noreferrer">https://training.sap.com/course/GW100</A></P><P>If you are more interested in a digital learning, please visit <A href="https://learning.sap.com" target="_blank" rel="noopener noreferrer">https://learning.sap.com</A>. Some parts of the GW100 are already available free-of-charge:</P><P><A href="https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway" target="_blank" rel="noopener noreferrer">https://learning.sap.com/learning-journeys/building-odata-services-with-sap-gateway</A></P><P>For any other questions around the offerings of SAP Learning Services, please jump to our community page and get in contact with us:</P><P><A href="https://pages.community.sap.com/topics/training-certification" target="_blank" rel="noopener noreferrer">https://pages.community.sap.com/topics/training-certification</A></P><P>I hope even if you won’t attend the GW100 in any kind, you found some useful information around SAP Gateway in this blog post.</P><P>Happy learning<BR />Stefan</P> 2024-02-29T15:33:56.276000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/can-i-extend-a-certain-app-with-clean-core-how/ba-p/13627922 Can I extend a certain app? With Clean Core? How? 2024-03-05T18:31:05.449000+01:00 mlauber https://community.sap.com/t5/user/viewprofilepage/user-id/157846 <P>Extensibility is a very important part in SAP S/4HANA. Although we recommend to have a fit-to-Standard approach, we know that not everything can be covered; there is a need for extensibility. But we don't just want to go hack about our system (anymore), we want to do it <STRONG>Clean Core compliant</STRONG>, meaning:</P><UL><LI>Extensions are clearly separated from SAP's code</LI><LI>Extensions do not modify any SAP objects</LI><LI>Extensions use only stable, released SAP APIs and extension points</LI></UL><P><EM>Please note for on-premise and private cloud customers</EM>: I want to be honest and add here that not absolutely everything can be achieved Clean Core compliant <EM><STRONG>yet</STRONG> </EM>for those systems. One such example are so called classic coding blocks in Finance, which are still used and can be "published" as key user extensibility with transaction SCFD_EUI. That said, this blog post focuses on trying to solve your requirement with Clean Core; always try that first!</P><P>But so now, how to go about this? Well, I'm hoping to give some help on that. In this blog post I'm focusing on extending an SAP S/4HANA Standard app, as an example.</P><P>&nbsp;</P><H1 id="toc-hId-858978945">First of...</H1><P>I want to start by saying that the below "guide" isn't exactly a guide, but rather a collection of ideas. I want to be fully honest and say that there are tons of ways to do an extension, and depending on your exact situation, one may be favored over another. So, do not see this as "the only way", but "a way" that could help you solve your extension need.</P><P>Please also note, as mentioned before, we are focusing on an extension for an existing standard app. Some extensions may include data from other systems than your S/4HANA and maybe are viable for side-by-side development (development in SAP BTP) using SAP Build, BAS, Integration Suite and/or other services. I will not touch on those scenarios in this blog, but we focus on extending directly in your S/4HANA system.</P><P>&nbsp;</P><H1 id="toc-hId-662465440">I found an app and I want to extend it - can I?</H1><P>This is often the very first question that reaches me; can I extend app Fxxxx? The simple truth is, there isn't a super simple answer. There are several ways to go about checking if your app can be extended, here are some:</P><H2 id="toc-hId-595034654">Part 1: Check Key User Extensibility</H2><P>Make sure your user as the required roles for key user extensibility (SAP_UI_FLEX_KEY_USER for being able to adapt the UI and SAP_BR_EXTENSIBILITY_SPEC for being able to use extensibility apps such as Custom Fields and Custom Logic).<BR />Open the app and the screen you wish to extend. In your user menu, select Adapt UI:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_0-1709627038571.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75363i9EEA6247A857B620/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_0-1709627038571.png" alt="mlauber_0-1709627038571.png" /></span></P><P>If this option is available, the app probably can be extended with Key User Extensibility (apps still can react differently on different UI sections and fields, and you simply need to try and see what’s possible when the mode is activated). If this option is not available, we come to that further below.<BR />Whether you want to add a new field or define new logic for your extension, right click onto an appropriate group, and press "+ Add: Field" (if this option is greyed out/disabled, new fields can’t be added for that group of data):</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_1-1709627174812.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75364i70634E6D9193DD6D/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_1-1709627174812.png" alt="mlauber_1-1709627174812.png" /></span></P><P>In the next dialog you will see a list of existing fields which are currently not on the screen.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_2-1709627230117.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75366iE1487528484592DD/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_2-1709627230117.png" alt="mlauber_2-1709627230117.png" /></span></P><P>To add a new custom field, you can click on the plus icon in the upper right corner -&gt; this will take you to the Custom Fields app in a new tab in your browser.&nbsp;When opening the app this way, the app is prepared to only show the <FONT color="#008080"><STRONG>business context</STRONG> </FONT>of the app you are trying to extend:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_3-1709627286911.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75367i055140154EC0AA48/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_3-1709627286911.png" alt="mlauber_3-1709627286911.png" /></span></P><P>By clicking the plus icon in the upper right corner here, you can <STRONG>add your custom field</STRONG> (there are lots of guides on how to do this, I don't focus on that in this blog post).</P><P>If the option "+ Add: Field" was greyed out, you can still check whether you can add your own logic by opening the Custom Logic app (use the new version, not depreciated, if available in your system -&gt; check the <A href="https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/#" target="_blank" rel="noopener nofollow noreferrer">Fiori Apps Reference Library</A>).&nbsp;Using <STRONG>Adapt UI</STRONG> first, gives the advantage of you giving you the corresponding business context, which you must otherwise select manually.</P><P>Clicking on Create in the Custom Logic app lists all extension points released for Key User extensibility. You can search by free text or via Business Context to see if you find an extension point that fulfills your requirement:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_4-1709627535179.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75374i4B439FC7288750FB/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_4-1709627535179.png" alt="mlauber_4-1709627535179.png" /></span></P><P>If you found what you need, <STRONG>create a new custom logic</STRONG> and write your code there (there are lots of guides on how to do this, I don't focus on that in this blog post).</P><P>If none of the extension points fit, you can continue to see if Developer Extensibility is possible...</P><H2 id="toc-hId-398521149">Part 2: Check On-Stack Developer Extensibility</H2><P>Go to the <A href="https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/#" target="_blank" rel="noopener nofollow noreferrer">Fiori Apps Reference Library</A>&nbsp;and find your app there, for example:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_5-1709627779713.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75382i7069D3EED12B5806/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_5-1709627779713.png" alt="mlauber_5-1709627779713.png" /></span></P><P>Make sure you are on the correct <FONT color="#3366FF">SAP S/4HANA release</FONT> for your solution (blue box). Open <STRONG>Implementation Information</STRONG>&nbsp;tab and check all the yellow marked boxes:</P><UL><LI>If the <STRONG>Application Type</STRONG> isn’t <FONT color="#3366FF">SAP Fiori</FONT>, it could be more difficult or not possible to extend (especially for Web-Dynpro apps – GUI transactions can possibly be modified with SAP Screen Personas for simpler requests)</LI><LI>Under <STRONG>Extensibility</STRONG> you <U>may</U> find a documentation for extending the app (an SAP Help page) and you <U>may</U> find the technical name of the frontend application (BSP containing SAPUI5 application), which can be used for Adaptation Projects in SAP BTP BAS.</LI><LI>Under <STRONG>Configuration</STRONG> you can find the OData Service(s) of the app. These contain the data model and underlying business logic for the app. A developer can analyze the main OData Service (sometimes there are several listed, for example an extra service for handling attachments that has otherwise nothing to do with the main business context of the app) to see whether it is extensible.</LI></UL><H3 id="toc-hId-331090363">In-Depth development objects analysis</H3><P>Checking the Fiori apps reference library should have given you some idea if the app can be extended with developer extensibility. You now need a developer to check further. At this point, I want to mention once more that below steps are not the only way to do these checks, but a possibility.</P><P>At this point we assume that our requirement cannot be solved with Key User extensibility. So now we want to check if we can extend the underlying OData service of the app to achieve our need.</P><P>Usually I start by determining in which <STRONG>Programming Model</STRONG> the OData service of the app was created:</P><UL><LI>Old Programming Model with a code-based OData service created in transaction SEGW</LI><LI>ABAP RESTful Application Programming Model (RAP) / ABAP Cloud development model</LI></UL><P>If the name of the OData service in the Fiori apps reference library ends with _CDS, we have a RAP service that was generated from a CDS view. If not, let's find out how the service was created (remember that this analysis is usually done by a developer):</P><OL><LI>In SAP GUI, open transaction <STRONG>se16n</STRONG> and enter table&nbsp;<STRONG>/IWBEP/I_SBD_GA</STRONG></LI><LI>Under TROBJ_NAME enter the name of the OData service</LI><LI>Under TROBJ_TYPE enter value IWSV for OData service</LI><LI>Hit Execute (F8)</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_6-1709628460384.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75416i973EDA7FF37ECA4F/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_6-1709628460384.png" alt="mlauber_6-1709628460384.png" /></span></P><P>If nothing is found, the OData service should have been made with RAP. If you find a record, you find the name of the SEGW project in the first column:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_7-1709628546043.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75419i2EF03CAB25C82485/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_7-1709628546043.png" alt="mlauber_7-1709628546043.png" /></span></P><H4 id="toc-hId-263659577">SEGW Project</H4><P>If the previous step led you to an SEGW project, open the transaction SEGW and open the project as found in the previous step.&nbsp;Depending on how the data model was built, we have more or less opportunities for extensions, for example:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_8-1709628602639.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75421i48A9D03FA7C2BE8C/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_8-1709628602639.png" alt="mlauber_8-1709628602639.png" /></span></P><UL><LI><STRONG>Data Model -&gt; Entity Types</STRONG>: these types were manually created (field by field) in SEGW&nbsp;without any underlying CDS view, meaning we cannot affect these data models without changing the SAP project, which we will not do in Clean Core!</LI><LI><STRONG>Data Resource Reference -&gt; Exposures via SADL -&gt; CDS Entity Exposures</STRONG>: if we have CDS entities listed here, we may have some extension possibilities. Continue to "Analyze RAP Objects" below.</LI></UL><P>Even if this step ended in only manual entity types, we still have the option to check if an <STRONG>Adaptation Project</STRONG> can do our requirement. More on those further below.</P><H4 id="toc-hId-67146072">Analyze RAP Objects (CDS, Business Service etc.)</H4><P>If either our whole OData service was made with RAP or we have some CDS entities that used by an older OData service, we may have some options for extensions.</P><P>In ABAP Development Tools for Eclipse (ADT), connect to your system.</P><H5 id="toc-hId--284714">Check OData Service</H5><P>Use <FONT color="#FF6600">Ctrl + Shift + A</FONT> to open any development object. Enter the name of the OData service, for example:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_9-1709629001237.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75426i1B9FB378EF3B7341/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_9-1709629001237.png" alt="mlauber_9-1709629001237.png" /></span></P><P>Open the object with the <FONT color="#800080">purple icon</FONT> for <STRONG>Service Binding</STRONG>.&nbsp;In the Service Binding you can find the <STRONG>Service Definition</STRONG> and all Entities exposed via this OData Service:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_10-1709629082696.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75427i3FACE8CB0F9533E3/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_10-1709629082696.png" alt="mlauber_10-1709629082696.png" /></span></P><P>In the lower part of the screen, you find a Properties tab. Here you can for example find the Development Package of the service, which can help to find further objects.</P><P>Let's start by opening the <STRONG>Service Definition</STRONG> we can see on the Service Binding.&nbsp;Sadly, it is currently not possible to navigate forward (F3) from the Service Binding to the Service Definition and it’s also not possible to copy the name of the Service Definition. Either retype it into&nbsp;<FONT color="#FF6600">Ctrl + Shift + A</FONT> or add the package from properties to your Favorite Packages (remember that not all RAP objects will be in that exact package, but most probably the Service Definition that belongs to the Service Binding will be):</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_11-1709629262222.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75429i5469AEC2488EE0A6/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_11-1709629262222.png" alt="mlauber_11-1709629262222.png" /></span></P><P>Opening the Service Definition will list all the CDS objects exposed:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_12-1709629285437.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75430i559D5ADC6E2F5320/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_12-1709629285437.png" alt="mlauber_12-1709629285437.png" /></span></P><P>Start by checking the <STRONG>Properties</STRONG> of the Service Definition, and under it, the tab <STRONG>API State</STRONG>:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_13-1709629332953.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75431i47129A6CBB407B29/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_13-1709629332953.png" alt="mlauber_13-1709629332953.png" /></span></P><P>Here we can see all the "contracts" the object has been released for. In the above example, there is no <STRONG>Contract C0 for extensions</STRONG>, meaning this Service Definition cannot be extended.&nbsp;Not all is lost yet; this simply means we cannot expose additional CDS on this Service Definition, but we can still check the exposed CDS, if we can extend those (since they are exposed, if we extend them the change is reflected in the OData service because the underlying model changed).</P><H5 id="toc-hId--196798219">Check CDS entities</H5><P>From the Service Definition, we can click on a row with a CDS name and use forward navigation (F3) to open it. Once it’s open, we can check the <STRONG>API State</STRONG>&nbsp;here:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_14-1709629664876.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75435i117113B5E57D9C4B/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_14-1709629664876.png" alt="mlauber_14-1709629664876.png" /></span></P><P>In the above example we can see that the CDS can indeed be extended, but only by <STRONG>Key User Apps</STRONG>; <STRONG>Cloud Development</STRONG> is not enabled for this object. In this case, we are back to Part 1: using UI Adaptation, Custom Fields, Custom Logic etc. apps.</P><P>In the same way as shown above, you can check the API state of any SAP object, for example a CDS entity you found in a SEGW project.</P><P>Open the CDS directly with <FONT color="#FF6600">Ctrl + Shift + A</FONT> and enter its name, then check API State under Properties.</P><P>What about <STRONG>behavior or logic of an app</STRONG>? If the OData service is built with RAP, we can check&nbsp;the <STRONG>Behavior Definition</STRONG> of a CDS entity, whether it can be extended or not.&nbsp;Copy the name of the CDS entity and use again <FONT color="#FF6600">Ctrl + Shift + A</FONT> and enter the name to find the behavior definition for it (they should have the same name), for example:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_0-1709634571705.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75517iB833DD76DFEF3A66/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_0-1709634571705.png" alt="mlauber_0-1709634571705.png" /></span></P><P>The <FONT color="#800080">purple B</FONT> icon is for <STRONG>Behavior Definition</STRONG>. Open it and check its API state as explained before.</P><H4 id="toc-hId--522394443">Check Extension Points</H4><P>If your OData service is not made with RAP, or the behavior cannot be extended, then you have to look for <STRONG>released extension points</STRONG> to add your own logic. We already quickly looked at the Custom Logic app: the extension points listed there are released for Key User Extensibility. There could be more extension points available, for Developer Extensibility (as we've seen in the above contract C0, an object can be released for Key User or for Development, or for both).</P><P>My recommendation is to always check Key User first. If it is not sufficient, we need to try and find an extension point that is. How can we do that? Again, several options.</P><P>Check on&nbsp;<A href="https://api.sap.com/" target="_blank" rel="noopener noreferrer">Business Accelerator Hub</A>&nbsp;under <STRONG>Categories - Business Add-Ins</STRONG>, for example:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_1-1709635203872.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75529i76783CBF5C71C6E4/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_1-1709635203872.png" alt="mlauber_1-1709635203872.png" /></span></P><P>Once you found your extension point, you can see its <STRONG>Release State</STRONG> when you click on it:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_2-1709635317442.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75531i2556000ECA220BBD/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_2-1709635317442.png" alt="mlauber_2-1709635317442.png" /></span></P><P>The other option is to directly check in ADT via the "<STRONG>Released Objects</STRONG>" tree (which you may need to add by customizing your ADT tree):</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_3-1709635377593.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75532i3D0436F47AAA2BCB/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_3-1709635377593.png" alt="mlauber_3-1709635377593.png" /></span></P><P>&nbsp;</P><H2 id="toc-hId--629819029">Part 3: It's still not enough - what now?</H2><P>Once you’ve checked both Key User Extensibility and Developer Extensibility and are still not able to fulfill your requirement, you still have a couple of options:</P><OL><LI>Create your own app, reusing standard CDS as much as possible (but wrapping them inside custom namespace, for example ZR_SalesOrderTP for reusing R_SalesOrderTP or I_SalesOrder etc.)<OL><LI>Add your new fields and/or behavior to your custom CDS</LI><LI>If you need your own custom table, consider if using <STRONG>Custom Business Objects</STRONG> works for your case. If not, be sure to <STRONG>build the RAP object properly</STRONG> (Database table, Basic interface view, View entity, View projection, Behavior, Behavior projection). Remember that custom business objects can have automatic Change Document handling, as well as System Administrative Data (created at, by, changed at, by) handling out-of-the-box.<OL><LI><STRONG>How do I find my Custom Business Object in ADT?</STRONG> Open your Custom Business Object in the app and refer to Name of Technical Service:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_5-1709635787267.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75666i0791B753D54B82E2/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_5-1709635787267.png" alt="mlauber_5-1709635787267.png" /></span></LI><LI>In ADT, use again <FONT color="#FF6600">Ctrl + Shift + A</FONT> and enter the name, but discard the final _CDS:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_4-1709635774434.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75665iA10BEBCE34FED1A0/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_4-1709635774434.png" alt="mlauber_4-1709635774434.png" /></span><BR /><BR /></LI></OL></LI></OL></LI><LI>Try to extend the app by using an <STRONG>Adaptation Project with SAP Business Application Studio on SAP BTP</STRONG>. Keep in mind that Adaption Projects are mostly used to modify the UI and actions on the UI. If this does not fulfill your need, you may need to go with option 1 or 3.<BR /><BR /></LI><LI>There is a third, hybrid option: one other feature of Adaption Projects is to add your own OData service or even replace the main OData service. If you prefer to keep the standard app instead of making your own (and making a new version for it via the Adaptation Project), you could try this option. You would create your own OData service with RAP and then create an Adaptation Project for the standard app, combining option 1 and 2:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_6-1709636015083.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/75669i7C2D1F4182AC18A4/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_6-1709636015083.png" alt="mlauber_6-1709636015083.png" /></span><P>&nbsp;</P></LI></OL><P>&nbsp;</P><H1 id="toc-hId--532929527">Conclusion</H1><P>One last time, I'd like to remind everyone that the above described options may not be the only ones, but are here to help you find your way to a clean extension. In general, when "everything fails", check if you cannot create your own custom development; on-stack or maybe even side-by-side. This is preferable over modifying the core. A well established Change Management and development/extension governance should also be in place!</P><UL><LI>Have a standard first approach: if there is a standard app, use it<UL><LI>Be sure to keep checking for new released apps or app changes, which may replace a custom development or extension you built</LI><LI>Extend the standard app, when needed, before coding your own<BR /><BR /></LI></UL></LI><LI>Always review all your options before starting to code:<UL><LI>Is the extension really needed?</LI><LI>Technical feasibility: how should the extension be implemented?<BR /><BR /></LI></UL></LI><LI>Document your custom development and extensions well; this way you have a quick and easy overview and can see if a new release may replace an extension that was previously needed</LI></UL><P>Hope this helps! And this is also to show there is no "one exact answer for all", but it's case-by-case. Be sure to check with an expert, if you are unsure, and keep that core clean!</P> 2024-03-05T18:31:05.449000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-search-in-the-new-sap-community-for-the-latest-content-related-to-an/ba-p/13637243 How to search in the new SAP community for the latest content related to an SAP managed tag? 2024-03-13T17:46:57.400000+01:00 Andre_Fischer https://community.sap.com/t5/user/viewprofilepage/user-id/55 <P>The workaround is very simple. I am basically searching for the SAP managed tag as a string by surrounding the tag in question by double quotes, for example:<BR />"ABAP RESTful Application Programming Model".</P><P>In addition I choose a sortorder by Date so that the newest posts will show up first.</P><P>So the following link will produce a list of the latest posts that have used the SAP managed tag&nbsp;"ABAP RESTful Application Programming Model".</P><P>It is also possible to store such a search as an RSS Feed.</P><P data-unlink="true"><A href="https://community.sap.com/t5/forums/searchpage/tab/message?q=%22ABAP%20RESTful%20Application%20Programming%20Model%22&amp;noSynonym=false&amp;sort_by=-topicPostDate&amp;collapse_discussion=true&nbsp;" target="_blank">https://community.sap.com/t5/forums/searchpage/tab/message?q=%22ABAP%20RESTful%20Application%20Programming%20Model%22&amp;noSynonym=false&amp;sort_by=-topicPostDate&amp;collapse_discussion=true&nbsp;</A></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="search for sap managed tag.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/80144i8F2528E6A4776277/image-size/large?v=v2&amp;px=999" role="button" title="search for sap managed tag.png" alt="search for sap managed tag.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RSS Feed.png" style="width: 637px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/80145iDC561D53A8DFC927/image-size/large?v=v2&amp;px=999" role="button" title="RSS Feed.png" alt="RSS Feed.png" /></span></P> 2024-03-13T17:46:57.400000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-add-a-new-entity-to-the-rap-bo-of-a-customizing-table/ba-p/13639320 How to add a new entity to the RAP BO of a customizing table 2024-03-15T14:18:55.104000+01:00 patrick_winkler https://community.sap.com/t5/user/viewprofilepage/user-id/729521 <H1 id="toc-hId-859956280">Introduction</H1><P><SPAN>You have created a RAP BO based on one or more customizing tables by using the&nbsp;</SPAN><A href="https://help.sap.com/docs/btp/sap-business-technology-platform/generating-business-configuration-maintenance-object-with-generate-abap-repository-objects-wizard" target="_blank" rel="noopener noreferrer">BC Maintenance Object ADT Wizard</A><SPAN>&nbsp;as described in&nbsp;</SPAN><A href="https://developers.sap.com/group.abap-env-factory.html" target="_blank" rel="noopener noreferrer">this tutorial</A><SPAN>.</SPAN></P><P>You want to extend the RAP BO by adding an additional customizing table to the data model.</P><P>The <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/business-configuration-maintenance-object?version=Cloud" target="_self" rel="noopener noreferrer">business configuration maintenance object</A> supports RAP BO whose height of the composition tree is less than or equal to 2.&nbsp;For example, root entity A has two child entities B and C. Entity C has a child entity D. D cannot have any further child entities.<BR />Depending on the back-end version, while the ADT wizard can handle multiple tables at the same time, the most complex supported scenarios require a manual enhancement after generation.</P><P>This blog is relevant for:</P><UL><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP%25252C+ABAP+environment/pd-p/73555000100800001164" target="_blank">SAP BTP, ABAP environment</A><SPAN>&nbsp;</SPAN>&nbsp;</LI><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+S%25252F4HANA+Private+Cloud/pd-p/5c26062a-9855-4f39-8205-272938b6882f" target="_blank">SAP S/4HANA Private Cloud</A></LI><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+S%25252F4HANA+Public+Cloud/pd-p/08e2a51b-1ce5-4367-8b33-4ae7e8b702e0" target="_blank">SAP S/4HANA Public Cloud</A></LI></UL><P>Further reading:</P><UL><LI><A href="https://community.sap.com/t5/tag/business%20configuration%20maintenance%20object/tg-p/board-id/technology-blog-sap" target="_blank">Related blog posts</A></LI><LI>Learn how you can use<SPAN>&nbsp;</SPAN><A href="https://learning.sap.com/products/business-technology-platform/development/abap?url_id=text-sapcommunity-prdteng-ABAP" target="_blank" rel="noopener noreferrer">ABAP technology</A><SPAN>&nbsp;</SPAN>to develop innovative applications and business solutions across SAP’s portfolio on<SPAN>&nbsp;</SPAN><A href="https://learning.sap.com/products/business-technology-platform/development/abap" target="_blank" rel="noopener noreferrer">SAP Learning Site</A>.</LI></UL><H1 id="toc-hId-663442775">Example RAP BO</H1><P>You have used the following table ZCB_HEAD with the ADT wizard to generate a maintenance object:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Header' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #C @AbapCatalog.dataMaintenance : #ALLOWED define table zcb_head { key client : abap.clnt not null; key head_key : zcb_id not null; head_content : abap.char(30); last_changed_at : abp_lastchange_tstmpl; local_last_changed_at : abp_locinst_lastchange_tstmpl; }</code></pre><P>&nbsp;</P><P>The table ZCB_ITEM that you want to add has the following structure and is a child entity of table ZCB_HEAD:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Item' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #C @AbapCatalog.dataMaintenance : #ALLOWED define table zcb_item { key client : abap.clnt not null; @AbapCatalog.foreignKey.keyType : #KEY @AbapCatalog.foreignKey.screenCheck : false key head_key : zcb_id not null with foreign key zcb_head where client = zcb_item.client and head_key = zcb_item.head_key; key item_key : abap.numc(3) not null; item_content : abap.char(30); local_last_changed_at : abp_locinst_lastchange_tstmpl; }</code></pre><P>&nbsp;</P><H1 id="toc-hId-466929270">Data model &amp; behavior</H1><H3 id="toc-hId-528581203">CDS View</H3><P>Create a CDS view for table ZCB_ITEM with</P><UL><LI>an association to parent table ZCB_HEAD</LI><LI>an association to the singleton entity based on a calculated field SingletonID</LI><LI>if you do not have a projection layer, add the annotation&nbsp;@Metadata.allowExtensions: true</LI></UL><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Header' @AccessControl.authorizationCheck: #CHECK @Metadata.allowExtensions: true define view entity ZI_Item as select from zcb_item association to parent ZI_Header as _Header on $projection.HeadKey = _Header.HeadKey association [1..1] to ZI_Header_S as _HeaderAll on $projection.SingletonID = _HeaderAll.SingletonID { key head_key as HeadKey, key item_key as ItemKey, item_content as ItemContent, @Semantics.systemDateTime.localInstanceLastChangedAt: true @Consumption.hidden: true local_last_changed_at as LocalLastChangedAt, @Consumption.hidden: true 1 as SingletonID, _Header, _HeaderAll }</code></pre><P>&nbsp;</P><P>Add a composition to ZI_Item in the CDS View of table ZCB_HEAD:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Header' @AccessControl.authorizationCheck: #CHECK define view entity ZI_Header as select from zcb_head association to parent ZI_Header_S as _HeaderAll on $projection.SingletonID = _HeaderAll.SingletonID composition [0..*] of ZI_Item as _Item { key head_key as HeadKey, head_content as HeadContent, @Semantics.systemDateTime.lastChangedAt: true last_changed_at as LastChangedAt, @Semantics.systemDateTime.localInstanceLastChangedAt: true @Consumption.hidden: true local_last_changed_at as LocalLastChangedAt, @Consumption.hidden: true 1 as SingletonID, _HeaderAll, _Item }</code></pre><P>&nbsp;</P><P>If you have a projection layer, create a projection CDS view for ZI_Item with redirection to entity ZC_Header and the singleton entity. Save and activate.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #CHECK @Metadata.allowExtensions: true @EndUserText.label: 'Maintain Item' define view entity ZC_Item as projection on ZI_Item { key HeadKey, key ItemKey, ItemContent, @Consumption.hidden: true LocalLastChangedAt, @Consumption.hidden: true SingletonID, _Header : redirected to parent ZC_Header, _HeaderAll : redirected to ZC_Header_S }</code></pre><P>&nbsp;</P><P>If you have a projection layer, add a redirection to composition child ZI_Item in the projection CDS view of ZI_Header:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Maintain Header' @AccessControl.authorizationCheck: #CHECK @Metadata.allowExtensions: true define view entity ZC_Header as projection on ZI_Header { key HeadKey, HeadContent, LastChangedAt, @Consumption.hidden: true LocalLastChangedAt, @Consumption.hidden: true SingletonID, _HeaderAll : redirected to parent ZC_Header_S, _Item : redirected to composition child ZC_Item }</code></pre><P>&nbsp;</P><H2 id="toc-hId-202984979">Behavior definition</H2><P>In the behavior definition ZI_HEADER_S, add the following definition for entity ZI_Item:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>define behavior for ZI_Item alias Item persistent table ZCB_ITEM draft table ZCB_ITEM_D etag master LocalLastChangedAt lock dependent by _HeaderAll authorization dependent by _HeaderAll { field ( mandatory : create ) ItemKey; field ( readonly ) SingletonID, HeadKey, LocalLastChangedAt; field ( readonly : update ) ItemKey; field ( notrigger ) SingletonID, LocalLastChangedAt; update( features : global ); delete( features : global ); mapping for ZCB_ITEM { HeadKey = HEAD_KEY; ItemKey = ITEM_KEY; ItemContent = ITEM_CONTENT; LocalLastChangedAt = LOCAL_LAST_CHANGED_AT; } association _HeaderAll { with draft; } association _Header { with draft; } validation ValidateTransportRequest on save ##NOT_ASSIGNED_TO_DETACT { create; update; delete; } }</code></pre><P>&nbsp;</P><P>In the entity definition of ZI_Header, add an association to ZI_Item:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>association _Item { create ( features : global ); with draft; }</code></pre><P>&nbsp;</P><P>Save the behavior definition. Place the cursor on the draft table ZCB_ITEM_D and use the quick assist (Ctrl+1) to generate the draft table. After activating the draft table, activate the behavior definition.<BR />Place the cursor on ZI_Item underlined by a warning message and use the quick assist to generate the missing method implementations.</P><P>If you have a projection layer, adjust the behavior projection:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>projection; strict; use draft; define behavior for ZC_Header_S alias HeaderAll { use action Edit; use action Activate; use action Discard; use action Resume; use action Prepare; use action SelectCustomizingTransptReq; use association _Header { create; with draft; } } define behavior for ZC_Header alias Header { use update; use delete; use association _HeaderAll { with draft; } use association _Item { create; with draft; } } define behavior for ZC_Item alias Item { use update; use delete; use association _HeaderAll { with draft; } use association _Header { with draft; } }</code></pre><P>&nbsp;</P><H2 id="toc-hId-6471474">Behavior implementation</H2><P>Edit the behavior implementation class.&nbsp;<BR />Add the table entity relation for ZCB_ITEM:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS LHC_RAP_TDAT_CTS IMPLEMENTATION. METHOD GET. result = mbc_cp_api=&gt;rap_tdat_cts( tdat_name = 'ZHEADER' table_entity_relations = VALUE #( ( entity = 'Header' table = 'ZCB_HEAD' ) ( entity = 'Item' table = 'ZCB_ITEM' ) ) ) ##NO_TEXT. ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>Implement the methods of LHC_ZI_ITEM and move the class definition LHC_RAP_TDAT_CTS up:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS lhc_rap_tdat_cts DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: get RETURNING VALUE(result) TYPE REF TO if_mbc_cp_rap_tdat_cts. ENDCLASS. CLASS lhc_item DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS get_global_features FOR GLOBAL FEATURES IMPORTING REQUEST requested_features FOR Item RESULT result. METHODS ValidateTransportRequest FOR VALIDATE ON SAVE IMPORTING keys FOR Item~ValidateTransportRequest. ENDCLASS. CLASS lhc_item IMPLEMENTATION. METHOD get_global_features. DATA edit_flag TYPE abp_behv_flag VALUE if_abap_behv=&gt;fc-o-enabled. IF lhc_rap_tdat_cts=&gt;get( )-&gt;is_editable( ) = abap_false. edit_flag = if_abap_behv=&gt;fc-o-disabled. ENDIF. result-%update = edit_flag. result-%delete = edit_flag. ENDMETHOD. METHOD ValidateTransportRequest. DATA change TYPE REQUEST FOR CHANGE ZI_Header_S. SELECT SINGLE TransportRequestID FROM zcb_head_d_s WHERE SingletonID = 1 INTO (TransportRequestID). lhc_rap_tdat_cts=&gt;get( )-&gt;validate_changes( transport_request = TransportRequestID table = 'ZCB_ITEM' keys = REF #( keys ) reported = REF #( reported ) failed = REF #( failed ) change = REF #( change-item ) ). ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>If you are using the VALIDATE_ALL_CHANGES method, delete the ValidateTransportRequest method from the LHC_ITEM class and adjust the ValidateTransportRequest method of the LHC_ZI_HEADER class:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>VALIDATETRANSPORTREQUEST FOR VALIDATE ON SAVE IMPORTING KEYS_HEADER FOR Header~ValidateTransportRequest KEYS_ITEM FOR Item~ValidateTransportRequest. [...] METHOD VALIDATETRANSPORTREQUEST. DATA change TYPE REQUEST FOR CHANGE ZI_Header_S. IF keys_Header IS NOT INITIAL. DATA(is_draft) = keys_Header[ 1 ]-%IS_DRAFT. ELSEIF keys_Item IS NOT INITIAL. is_draft = keys_Item[ 1 ]-%IS_DRAFT. ELSE. RETURN. ENDIF. READ ENTITY IN LOCAL MODE ZI_Header_S FROM VALUE #( ( %IS_DRAFT = is_draft SingletonID = 1 %CONTROL-TransportRequestID = if_abap_behv=&gt;mk-on ) ) RESULT FINAL(transport_from_singleton). IF lines( transport_from_singleton ) = 1. DATA(transport_request) = transport_from_singleton[ 1 ]-TransportRequestID. ENDIF. lhc_rap_tdat_cts=&gt;get( )-&gt;validate_all_changes( transport_request = transport_request table_validation_keys = VALUE #( ( table = 'ZCB_HEAD' keys = REF #( keys_Header ) ) ( table = 'ZCB_ITEM' keys = REF #( keys_Item ) ) ) reported = REF #( reported ) failed = REF #( failed ) change = REF #( change ) ). ENDMETHOD.</code></pre><P>&nbsp;</P><P>Add the %ASSOC-_Item statement to the GET_GLOBAL_FEATURES method of LHC_ZI_HEADER:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> METHOD get_global_features. DATA edit_flag TYPE abp_behv_flag VALUE if_abap_behv=&gt;fc-o-enabled. IF lhc_rap_tdat_cts=&gt;get( )-&gt;is_editable( ) = abap_false. edit_flag = if_abap_behv=&gt;fc-o-disabled. ENDIF. result-%update = edit_flag. result-%delete = edit_flag. result-%ASSOC-_Item = edit_flag. ENDMETHOD.</code></pre><P>&nbsp;</P><H2 id="toc-hId--190042031">Metadata extension</H2><P>Create a metadata extension for ZI_Item or ZC_Item when using a projection layer:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CUSTOMER @UI: { headerInfo: { typeName: 'Item', typeNamePlural: 'Items', title: { type: #STANDARD, label: 'Item', value: 'ItemKey' } } } annotate entity ZC_Item with { @UI.identification: [ { position: 1 , label: 'ItemKey' } ] @UI.lineItem: [ { position: 1 , label: 'ItemKey' } ] @UI.facet: [ { id: 'ZI_Item', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Item', position: 1 } ] ItemKey; @UI.identification: [ { position: 2 , label: 'ItemContent' } ] @UI.lineItem: [ { position: 2 , label: 'ItemContent' } ] ItemContent; }</code></pre><P>&nbsp;</P><P>Add a facet to _Item in the metadata extension of ZI_Header or ZC_Header when using a projection layer:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>[...] annotate entity ZC_Header with { @UI.identification: [ { position: 1 } ] @UI.lineItem: [ { position: 1 } ] @UI.facet: [ { id: 'ZI_Header', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Header', position: 1 }, { id: 'ZI_Item', type: #LINEITEM_REFERENCE, label: 'Item', position: 2 , targetElement: '_Item' } ] HeadKey; [...]</code></pre><P>&nbsp;</P><H2 id="toc-hId--386555536">Access Control</H2><P>Create an access control object for ZI_Item:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@MappingRole: true define role ZI_Item { grant select on ZI_Item where INHERITING CONDITIONS FROM ENTITY ZI_Header; }</code></pre><P>&nbsp;</P><P>If you are using a projection layer, create an access control object for ZC_Item:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@MappingRole: true define role ZC_Item { grant select on ZC_Item where INHERITING CONDITIONS FROM ENTITY ZI_Item; }</code></pre><P>&nbsp;</P><H2 id="toc-hId--583069041">Transport Object</H2><P>Add table ZCB_ITEM to the transport object definition ZHEADER:</P><P>&nbsp;</P><pre class="lia-code-sample language-json"><code> "tableItems": [ { "tableName": "ZCB_HEAD", "isPrimaryTable": true }, { "tableName": "ZCB_ITEM" } ]</code></pre><P>&nbsp;</P><P>If you are using SAP S/4HANA On Premises 2023, use transaction SOBJ instead of ADT to adjust the transport object definition.</P><H2 id="toc-hId--779582546">Business Service</H2><P>Add entity ZC_Item to the service definition:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>define service ZUI_HEADER { expose ZC_Header_S as HeaderAll; expose ZC_Header as Header; expose ZC_Item as Item; }</code></pre><P>&nbsp;</P><H2 id="toc-hId--628841694">Maintenance Object</H2><P>No adjustments are necessary. You have the option to define specific table settings for the new entity, for example, to change the <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/table-creation-mode" target="_self" rel="noopener noreferrer">table creation mode</A>.</P><P>You can now restart the Custom Business Configurations app to review the changes.</P> 2024-03-15T14:18:55.104000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-enable-an-odata-v4-service-for-anonymous-access/ba-p/13643572 How to enable an OData V4 service for anonymous access? 2024-03-19T21:57:57.546000+01:00 Andre_Fischer https://community.sap.com/t5/user/viewprofilepage/user-id/55 <H1 id="toc-hId-860703134">Introduction</H1><P>This requirement stems from a customer that asked how to publish an OData V4 service in an SAP S/4HANA on premise system such that it could be used on a public web site without the need to provide any authentication.</P><P>With OData V2 this requirement can be achieved more easily since here every service has it's own SICF node where it would be possible to store credentials just for this service.</P><P>In OData V4 we have only one SICF node, namely&nbsp;<STRONG>/sap/opu/odata4/.</STRONG></P><P>This is obviously a problem since there is no service specific node available in SICF.</P><H1 id="toc-hId-664189629">Solution</H1><P>The problem can be solved using the following approach.</P><OL><LI>Create a role that only contains the <STRONG>S_START</STRONG> authorization for the one single OData V4 service we want to publish ,&nbsp;<BR /><A href="https://help.sap.com/doc/saphelp_nw75/7.5.5/de-DE/c6/dd838722ce4b8d9cc4a0741d93d864/frameset.htm" target="_blank" rel="noopener noreferrer">help.sap.com/doc/saphelp_nw75/7.5.5/de-DE/c6/dd838722ce4b8d9cc4a0741d93d864/frameset.htm</A></LI><LI>Create a technical user that has only the authorization to access the single OData V4 service we want to make accessible.</LI><LI>Create an alias in SICF for the node&nbsp;<STRONG>/sap/opu/odata4/&nbsp;</STRONG></LI><LI>Store the credentials of the aforementioned user in the alias</LI><LI>Test the service&nbsp;&nbsp;</LI></OL><H1 id="toc-hId-467676124">Result</H1><P>As we can see accessing the service&nbsp;<STRONG>zrap630ui_shop_o4_05a</STRONG> via the alias <STRONG>zodatav4&nbsp;</STRONG>works.</P><P><A href="https://10.79.21.221:44301/sap/opu/zodatav4/sap/zrap630ui_shop_o4_05a/srvd/sap/zrap630ui_shop_o4_05a/0001/?sap-client=100" target="_blank" rel="noopener nofollow noreferrer">https://10.79.21.221:44301/sap/opu/zodatav4/sap/zrap630ui_shop_o4_05a/srvd/sap/zrap630ui_shop_o4_05a/0001/?sap-client=100</A></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="100_test_service_1.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83418i76C5523CCA831AAC/image-size/large?v=v2&amp;px=999" role="button" title="100_test_service_1.png" alt="100_test_service_1.png" /></span></P><P>Whereas accessing a second OData V4 service&nbsp;<STRONG>zrap630ui_shop_o4_05b</STRONG> via the alias <STRONG>zodatav4 </STRONG>does <STRONG>NOT work</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="110_test_service_1.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83419i3EE98F3B6179053B/image-size/large?v=v2&amp;px=999" role="button" title="110_test_service_1.png" alt="110_test_service_1.png" /></span></P><P>This has been achieved by assigne the follwoing role the technical user which only contains the authorization to start the first service based on the authorization object <STRONG>S_START</STRONG>.</P><P style=" padding-left : 30px; "><STRONG>Please note:</STRONG><BR />Since OData V4 service use the authorization object S_START which is based on the service name it would for example be possible to publish several services that are in the same name range like</P><P style=" padding-left : 30px; ">zrap630ui_shop_o4_<STRONG>05A</STRONG>,&nbsp;zrap630ui_shop_o4_<STRONG>05B</STRONG>, ...&nbsp;zrap630ui_shop_o4_<STRONG>05Z</STRONG>,&nbsp;&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="120_role_2.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83420i0B3411C8E6E88B6F/image-size/large?v=v2&amp;px=999" role="button" title="120_role_2.png" alt="120_role_2.png" /></span></P><H1 id="toc-hId-271162619"><STRONG>How to section</STRONG></H1><H3 id="toc-hId-332814552"><STRONG>Create the role</STRONG></H3><P>Using PFCG and the role template <SPAN class="">/IWBEP/RT_MGW_USR we create a role as shown in the screen shot above that only contains the S_START authorization of one OData V4 service called&nbsp;ZRAP630UI_SHOP_O4_05A.<BR /></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="120_role_1.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83433iF66B19D135CCA30E/image-size/large?v=v2&amp;px=999" role="button" title="120_role_1.png" alt="120_role_1.png" /></span></P><H3 id="toc-hId-136301047"><STRONG>Create</STRONG> the<STRONG> user</STRONG></H3><P>As a user we create a technical user whose credentials will be stored in the system alias.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="130_technical_user.png" style="width: 876px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83436iC507E93B64E11FAF/image-size/large?v=v2&amp;px=999" role="button" title="130_technical_user.png" alt="130_technical_user.png" /></span></P><H3 id="toc-hId--60212458"><STRONG>Create the system alias</STRONG></H3><P>1. We start by right-clicking on the node <STRONG>opu</STRONG> and choose <STRONG>New subelement</STRONG>.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="010_Create_Alias.png" style="width: 643px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83424i3B2863743E4C897D/image-size/large?v=v2&amp;px=999" role="button" title="010_Create_Alias.png" alt="010_Create_Alias.png" /></span></STRONG></P><P>2. We create a new service element called <STRONG>ZODATAV4_2&nbsp;</STRONG>and choose the option <STRONG>Alias to an existing service</STRONG>.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="020_create_alias.png" style="width: 877px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83423i28731E07AD83EAC7/image-size/large?v=v2&amp;px=999" role="button" title="020_create_alias.png" alt="020_create_alias.png" /></span></STRONG></P><P>3. We choose the tab <STRONG>Target</STRONG>, select the node <STRONG>OdataV4</STRONG> by double-clicking on it.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="030_create_alias.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83426i2C2315451CB01CBA/image-size/large?v=v2&amp;px=999" role="button" title="030_create_alias.png" alt="030_create_alias.png" /></span></STRONG></P><P>4. We navigate to the tab <STRONG>Logon Data</STRONG>, choose <STRONG>Alternative Logon Procedure</STRONG> and enter the credentials of our service user.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="050_create_alias.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83427iF7847BF82D023A46/image-size/large?v=v2&amp;px=999" role="button" title="050_create_alias.png" alt="050_create_alias.png" /></span></STRONG></P><P>5. We navigate down and remove all logon procedures beside <STRONG>Logon using service data</STRONG>.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="060_create_alias.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83428i4185C25916590275/image-size/large?v=v2&amp;px=999" role="button" title="060_create_alias.png" alt="060_create_alias.png" /></span></STRONG></P><P>6. Do not forget to activate the link in SICF.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="070_create_alias.png" style="width: 484px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83429i1BBD6FF69034F2EA/image-size/large?v=v2&amp;px=999" role="button" title="070_create_alias.png" alt="070_create_alias.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="080_create_alias.png" style="width: 747px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83430i0F969188176ECB1E/image-size/large?v=v2&amp;px=999" role="button" title="080_create_alias.png" alt="080_create_alias.png" /></span></STRONG></P><P>7. Check the result</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="090_create_alias.png" style="width: 909px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/83431i5366E830240FD49A/image-size/large?v=v2&amp;px=999" role="button" title="090_create_alias.png" alt="090_create_alias.png" /></span></STRONG></P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2024-03-19T21:57:57.546000+01:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-get-a-quot-display-only-quot-fiori-app-from-a-quot-manage-quot-fiori/ba-p/13645765 How to get a "Display only" Fiori app from a "Manage" Fiori app 2024-03-22T09:32:32.218000+01:00 mlauber https://community.sap.com/t5/user/viewprofilepage/user-id/157846 <P>Ever come across a really good Standard Fiori app which you would like to use both for users that are allowed to create new business context, but also for those who should only display them? Sometimes there is a "display" or "List" app available, but not always. In this blog you'll learn how you can create your own "display only" app without having to redo everything SAP standard "did for you".</P><P>&nbsp;</P><H1 id="toc-hId-860764610">Example Case</H1><P>In this example I'll be using "Manage Sales Order" app (<SPAN>F3893)</SPAN>:&nbsp;<A href="https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/#/detail/Apps('F3893')/S28OP" target="_blank" rel="noopener nofollow noreferrer">Manage Sales Orders - Version 2</A>&nbsp;</P><P>&nbsp;</P><H1 id="toc-hId-664251105">CDS Development</H1><H2 id="toc-hId-596820319">Step 1: Get Main CDS</H2><P>The first thing we have to do is to figure out the main CDS view of the original standard app. In this example it's very simple because with have an OData service that was developed with RAP according to ABAP Cloud:&nbsp;<STRONG>C_SALESORDERMANAGE_SRV</STRONG>. We open this object in ADT and soon find the main CDS:&nbsp;<STRONG>C_SalesOrderManage</STRONG>.</P><P>I won't go into details here how to find the main CDS. In another blog post I have explained how to check an OData service and find CDS, please check <A href="https://community.sap.com/t5/technology-blogs-by-sap/can-i-extend-a-certain-app-with-clean-core-how/ba-p/13627922" target="_blank">there</A>. If you still need help, maybe I make a new blog for that topic alone, we'll see.</P><H2 id="toc-hId-400306814">Step 2: Decide Approach (yes, there is more than one)</H2><P>Now that we have&nbsp;C_SalesOrderManage open (this is a projection view), we can check from which CDS it gets the data; R_SalesOrderTP. Looking at that CDS tells us that this is a <STRONG>root view entity</STRONG> which has <STRONG>composition children</STRONG>. So we can't just select from&nbsp;R_SalesOrderTP in our own CDS and reuse the compositions. For example&nbsp;R_SalesOrderItemTP is linked to&nbsp;R_SalesOrderTP and we cannot change SAP Standard so that it links to our own CDS. Meaning we go 1 level lower to the basic interface view that is used by R_SalesOrderTP; I_SalesOrder. Here some help how the CDS looks like:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_0-1711023603352.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84408iB61B764D3419620E/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_0-1711023603352.png" alt="mlauber_0-1711023603352.png" /></span></P><P>We can see that for "as select from" we have&nbsp;<SPAN><STRONG>I_SalesOrder</STRONG>. This is the one we want to use, because looking at it confirms it's no root view entity, but a regular CDS view/entity which we can reuse for our purpose.</SPAN></P><P>At this point we should make a choice:</P><UL><LI>Do we want to have full functionality as in the original app, for example navigating from a sales order details page, all the way into a sales order item details page?</LI><LI>Or is it enough with one list report and one detail page? Namely in this example, a way to search for sales orders via filters, then clicking on a sales order and display all wanted details, but no further navigation.</LI></UL><P>Important: both are possible.</P><UL><LI>Choice one, full functionality: this means more wrappers and more work. You will basically create your own root view entity, with your own composite child entities (all wrapping around standard ones so you don't create them from scratch, thus called wrapper) for all the data you wish to display in your display-only app. You will then create the proper projection view, just like&nbsp;C_SalesOrderManage, create service definition and binding, which then gives you your OData service for the Fiori app.</LI><LI>Choice two: if we just need a simple list report with details page, we can generate an OData service directly from a CDS view entity. In this example I will go with this option, for simpleness sake. But basically the steps are as said just above, creating a wrapper for all CDS you want in the end and creating a proper OData service with RAP and ABAP Cloud.</LI></UL><H2 id="toc-hId-203793309">Step 3: Create wrapper for CDS</H2><OL><LI>Create a new data definition:&nbsp;ZC_SalesOrderTP (we give it C in its name for "consumption" because we will directly expose this CDS as OData service, and "TP" for transactional processing).</LI><LI>As reference CDS view, be sure to enter&nbsp;<SPAN><STRONG>I_SalesOrder</STRONG></SPAN> as identified in the previous step. If you do, ADT will add all fields and associations for you.</LI><LI>First off, at the beginning of your view entity you will need below two semantics. The first will make sure we don't just blindly take over all semantics from I_SalesOrder (this could be handy and potentially faster, but since we may not use absolutely all associations etc., it is in my opinion better to recreate your own semantics and thus the syntax checker will also help you to make sure everything is correct). The second one allows us to create an extra metadata extension file, which we can use for all UI annotations, which makes the whole thing less messy. I always recommend to separate UI annotations from other semantics.</LI></OL><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true​</code></pre><P>&nbsp;</P><UL><LI>Next we add that we want to publish this CDS as OData service (with <STRONG>@OData.publish: true</STRONG>). This is only needed if you are going the more simple option. Otherwise you leave this out and create the OData service via Service Definition and Binding, once you built the complete RAP object.</LI><LI>Next I copied some of the semantics from the standard CDS and here is the complete start of my CDS so far:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_1-1711024804490.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84415i375EC8133FBB4288/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_1-1711024804490.png" alt="mlauber_1-1711024804490.png" /></span></LI><LI>Add the associations you want to use (again, simply copy from standard CDS) - if you are doing the more functionality route, be sure to use composite child instead of association and you have to create z-wrappers for each, and use the z-CDS here, not for example R_SalesOrderItemTP:</LI></UL><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>association [0..*] to I_SalesOrderItem as _Item on $projection.SalesOrder = _Item.SalesOrder association [0..*] to R_SalesOrderTextTP as _Text on $projection.SalesOrder = _Text.SalesOrder association [0..*] to I_SalesOrderPartner as _Partner on $projection.SalesOrder = _Partner.SalesOrder association [0..1] to I_SalesOrderPartner as _SoldToParty on $projection.SalesOrder = _SoldToParty.SalesOrder and _SoldToParty.PartnerFunction = 'AG' association [0..1] to C_SlsDocStdPartnerContactInfo as _SoldToPartyContactInfo on $projection.SalesOrder = _SoldToPartyContactInfo.SalesDocument and $projection.SoldToParty = _SoldToPartyContactInfo.SoldToParty and $projection.SalesOrderType = _SoldToPartyContactInfo.SalesDocumentType association [0..1] to I_SalesOrderPartner as _ShipToParty on $projection.SalesOrder = _ShipToParty.SalesOrder and _ShipToParty.PartnerFunction = 'WE' association [0..1] to I_SlsOrganizationDistrChnl as _SlsOrganizationDistrChnl on $projection.SalesOrganization = _SlsOrganizationDistrChnl.SalesOrganization and $projection.DistributionChannel = _SlsOrganizationDistrChnl.DistributionChannel //Extension Association association [1] to E_SalesDocumentBasic as _Extension on $projection.SalesOrder = _Extension.SalesDocument​</code></pre><P>&nbsp;</P><UL><LI>Now I do the same per field that is important: add semantics to have a good UX. Here a couple of examples (I won't add everything as it would just get too big):</LI></UL><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Search: { defaultSearchElement: true, fuzzinessThreshold: 0.9, ranking: #HIGH } key SalesOrder.SalesOrder, @ObjectModel.text.element: ['CustomerName'] @Search: { defaultSearchElement: true, fuzzinessThreshold: 0.8 } SalesOrder.SoldToParty, @Semantics.text:true _SoldToParty.FullName as CustomerName,​</code></pre><P>&nbsp;</P><P>If you go the more functionality route, you keep creating your z-version for each "composition [0..*] of " that you feel you want to use in your display-only app. Once the wrappers are done, you can come back to the main one and activate it with the correct children-links.</P><H2 id="toc-hId-7279804">Step 4: Authorization</H2><P>If you paid attention above, we of course want to make sure that users still only see the sales orders they are supposed to see; the standard authorization. Once again, we don't need to redo this, we can inherit the standard one.</P><P>In ADT, create a new Access Control with the same name as your CDS you want to be checked, in my case <STRONG>ZC_SalesOrderTP</STRONG>. Then simply enter the "inheriting conditions from entity", save and done:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Sales Order for Display Access' @MappingRole: true define role ZC_SALESORDERTP { grant select on ZC_SalesOrderTP where inheriting conditions from entity R_SalesOrderTP; }</code></pre><P>&nbsp;</P><H2 id="toc-hId--189233701">Step 5: UI Annotations for Fiori</H2><P>I recommend to add all UI annotations that you want Fiori display via a <STRONG>metadata extension</STRONG> file. In ADT, create a metadata extension file that has the exact same name as your CDS, in my case&nbsp;<STRONG>ZC_SalesOrderTP</STRONG>. Here once again I opened the standard metadata extension file with <EM>Ctrl + Shift + A</EM> in ADT, and entering the same name as the main CDS: C_SalesOrderManage. In the dialog that shows all the hits, choose the metadata extension file instead of the Data Definition.</P><P>Now, at this point you may need some extra time. Instead of blindly copying all the annotations from the standard file, I went through and only added the facets that I wanted on my display-only app, and only the fields that I wanted. If you add too much (meaning you add annotations to something that doesn't exist in your z-wrapper CDS) syntax check will catch it but, there can be some "hidden" errors. And those will result in your Fiori app not functioning properly. For example, let's say you add a certain facet:</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>{ id: 'CompletionStatus', label: 'Completion Status', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, parentId: 'StatusTab', importance: #HIGH, position: 30, targetQualifier: 'CompletionStatus' },</code></pre><P>&nbsp;</P><P>The above looks all fine and will pass syntax check. We have the "CompletionStatus" and we can add fields to this facet. BUT, if you paid close attention, you may noticed this line:&nbsp;<STRONG>parentId: 'StatusTab'</STRONG>. This means our&nbsp;CompletionStatus facet is inside another, a parent facet. If you now didn't copy that parent facet, and there is no facet with id&nbsp;StatusTab, then your Fiori application will not work properly, because it cannot resolve this.</P><P>This is probably the part where you spend most of your time on. Myself when I did this example it took me about 1-2 hours.</P><H2 id="toc-hId--385747206">Step 6: Publish OData Service</H2><P>Next we need to publish our custom OData service with transaction <STRONG>/IWFND/MAINT_SERVICE</STRONG>&nbsp;for OData V2 services or&nbsp;<STRONG>/IWFND/V4_ADMIN</STRONG> for OData V4. Note that when using&nbsp;<STRONG>@OData.publish: true</STRONG>&nbsp;the system will add <STRONG>_CDS</STRONG> to your OData service name. Confirm your service and metadata was loaded successfully before continuing.&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_2-1711025801015.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84468i9457B0D8FAAA7A3D/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_2-1711025801015.png" alt="mlauber_2-1711025801015.png" /></span></P><P>&nbsp;</P><H1 id="toc-hId--711343430">Fiori Development</H1><P>Next up, we create our display-only Fiori elements app.</P><P>Open <STRONG>Business Application Studio (BAS)</STRONG>&nbsp;on your SAP BTP and start a space for Fiori development.</P><P>Create a new Project from Template and choose <STRONG>SAP Fiori application</STRONG>. The first thing we need to do is connect to a data source. In my case an S/4HANA on-premise system that I have connected to my SAP BTP via Cloud Connector. I select in this step the <STRONG>Destination</STRONG> to that S/4HANA system via Cloud Connector, and then I select my OData service:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_4-1711027035961.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84482i4FA78DA730C70195/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_4-1711027035961.png" alt="mlauber_4-1711027035961.png" /></span></P><P>Next, we enter the project details, for example:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_3-1711026913484.png" style="width: 421px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84481i6D0CE7D2C93ACD34/image-dimensions/421x408?v=v2" width="421" height="408" role="button" title="mlauber_3-1711026913484.png" alt="mlauber_3-1711026913484.png" /></span></P><P>You should add deployment configuration and also FLP configuration here. I again select my S/4HANA system destination and enter a technical name for the Fiori app to be created on the ABAP platform of my S/4HANA system. You also need to enter package and transport at this point.</P><P>For the FLP configuration it's business as usual, except be careful with your semantic object and action. Be sure to not reuse what standard is using, for example I used SalesOrder as object (because that is correct) and then I said the action is "displayOnly" to be sure to not have another intent like that:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_5-1711027196571.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84484iB0EDAC5EE4ACC560/image-size/medium?v=v2&amp;px=400" role="button" title="mlauber_5-1711027196571.png" alt="mlauber_5-1711027196571.png" /></span></P><P>Once the wizard is done, simply test your app. Because we have done all the UI annotations, you should be good to go.</P><P>Deploy your app and we are almost done.</P><P>&nbsp;</P><H1 id="toc-hId--907856935">Adding your App to the Fiori Launchpad</H1><P>The app is now in our system but it has no catalog etc. So we gotta do this per usual practice. I won't go into super details here:</P><OL><LI>Create a technical catalog if you don't have a suitable one using&nbsp;<STRONG>Launchpad App Manager - Cross Client</STRONG></LI><LI>From your technical catalog, choose Add App to add an "app descriptor item", or Tile and Target Mapping in other words (so we are still in&nbsp;<STRONG>Launchpad App Manager - Cross Client</STRONG>&nbsp;we have created/navigated to our technical catalog, in edit mode and choose Add App)</LI><LI>Here under application component ID you have to enter the full application name you chose for your Fiori application when you first created it in BAS. In my case i had namespace "disp" and name "salesorderdisplay", meaning&nbsp;<STRONG>disp.salesorderdisplay</STRONG>. If you enter this, the app should fetch all the necessary FLP config you already did in BAS (it will also fetch ICF path for you):<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_6-1711027655971.png" style="width: 449px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84488iD75BB6F456ED30CE/image-dimensions/449x249?v=v2" width="449" height="249" role="button" title="mlauber_6-1711027655971.png" alt="mlauber_6-1711027655971.png" /></span></LI><LI>In my case, because I chose "Mange Sales Orders" app, I also added all the parameters which that app uses - be sure not to forget this!<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_7-1711027746195.png" style="width: 471px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84490i42CC88DECF8039E5/image-dimensions/471x177?v=v2" width="471" height="177" role="button" title="mlauber_7-1711027746195.png" alt="mlauber_7-1711027746195.png" /></span></LI><LI>Save this.</LI><LI>Next, we need to add the app to a business catalog (maybe create a new business catalog if needed) or several, depending on your setup</LI><LI>Then we need to add our business catalog(s) for this app to all the appropriate roles who should have this display-only app</LI><LI>Lastly, if the app should be on a Space and Page, we need to do that config</LI></OL><P>All done! You have a display-only app, using standard CDS which you have wrapped into a custom OData service, for a custom app.&nbsp;</P><P>And if you were wondering; <STRONG>Is this Clean Core</STRONG>? Then yes. Custom development that follows the ABAP Cloud programming model is "clean". One thing to consider when you create such "wrappers" (Tier 2) is to keep an eye out if SAP Standard delivers a solution that makes your custom development unnecessary; then you should switch to SAP Standard and retire your own development (and you will be on Tier 1).</P><P>&nbsp;</P><H1 id="toc-hId--334630357">Solution</H1><P>The final app - list report page (including smart links to customer, without us having to code it ourselves):</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_8-1711029611078.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84511i7B3CFAEE95DF61C2/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_8-1711029611078.png" alt="mlauber_8-1711029611078.png" /></span></P><P>Details/Object page:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mlauber_9-1711029665573.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/84512i1B4327EEC7AF22AD/image-size/large?v=v2&amp;px=999" role="button" title="mlauber_9-1711029665573.png" alt="mlauber_9-1711029665573.png" /></span></P><P>Hope this was helpful! Let me know if you wonder anything.</P> 2024-03-22T09:32:32.218000+01:00 https://community.sap.com/t5/application-development-blog-posts/step-by-step-process-to-publish-standard-business-events-from-s-4-hana-to/ba-p/13650346 Step by Step process to publish standard Business events from S/4 Hana to Event Mesh 2024-03-27T10:04:35.331000+01:00 BramhaniG https://community.sap.com/t5/user/viewprofilepage/user-id/566391 <P>Hi All,</P><P>This blog explains Outbound Configuration to send events from S/4 Hana on premise to Event Mesh and test the same.</P><P>You need to have below roles</P><P>1. SAP_IWXBE_RT_XBE_ADM</P><P>2. SAP_IWXBE_RT_XBE_BUSI</P><P>3. SAP_IWXBE_RT_XBE_MDT</P><P>In S/4 system, please follow below steps.</P><P>Create a Channel using T-code “/n/IWXBE/CONFIG”.</P><P>Click on “Via Service key”.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_0-1711475041180.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86881iE637E0E22D5CA546/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_0-1711475041180.png" alt="bramhani_0-1711475041180.png" /></span></P><P>Enter Channel name and Description. Get the Event mesh instance key from Basis team. Copy and paste the service key of event mesh as shown below.</P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_2-1711475317479.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86883i2A4F0859B8DB1D4A/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_2-1711475317479.png" alt="bramhani_2-1711475317479.png" /></span></P><P>select the channel and activate it.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_3-1711475479532.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86886i0EB2C5A2F4B43AD2/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_3-1711475479532.png" alt="bramhani_3-1711475479532.png" /></span></P><P>Once it is activated, click on Check connection. You will get the below message if connection successfull.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_4-1711475533545.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86889i3FFEC427FB94E325/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_4-1711475533545.png" alt="bramhani_4-1711475533545.png" /></span></P><P>To Create Outbound binding, please select channel and click on outbound bindings.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_5-1711475580760.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86891i82A06E121ECDF01D/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_5-1711475580760.png" alt="bramhani_5-1711475580760.png" /></span></P><P>Click on create and then F4.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_6-1711475600642.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86893i2C12F131954216BE/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_6-1711475600642.png" alt="bramhani_6-1711475600642.png" /></span></P><P>Select the topic from F4 and save it. If you don't find topics in F4 help, you need to implement note "<SPAN><SPAN class="">3346777".</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_7-1711475621319.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86895i97F762B74645C5E3/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_7-1711475621319.png" alt="bramhani_7-1711475621319.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_8-1711475708928.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86898i057971A6E824C6A4/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_8-1711475708928.png" alt="bramhani_8-1711475708928.png" /></span></P><P>&nbsp;</P><P>Now, you need to create a Queue in Event Mesh and subscribe the topic.</P><P>Open Event Mesh and click on Create Queue.</P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_1-1711476609138.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86913iB63510AA9161AA13/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_1-1711476609138.png" alt="bramhani_1-1711476609138.png" /></span></P><P>Provide some name and click on create</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_3-1711476811030.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86915iCB42CD50A1CDE183/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_3-1711476811030.png" alt="bramhani_3-1711476811030.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_5-1711476924298.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86918iB3F08499FD8C2378/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_5-1711476924298.png" alt="bramhani_5-1711476924298.png" /></span></P><P>Once the Queue is created, click on highlighted button and select Queue Subscriptions.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_6-1711476985619.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86919i396F8A8C4D570A86/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_6-1711476985619.png" alt="bramhani_6-1711476985619.png" /></span></P><P>Enter Topic name along with the namespace and click on add button to subscribe to the topic.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_8-1711477345992.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86924i50BC9AE2017C70C9/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_8-1711477345992.png" alt="bramhani_8-1711477345992.png" /></span></P><P>Configuration is done in S/4 Hana system and in the BTP Event Mesh.</P><P>To test the messages,&nbsp;</P><P>Trigger Standard Business Partner Events by creating a business partner using T-Code BP.</P><P>Click on Person.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_9-1711477440402.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86925iF2B92A1E6E5521EA/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_9-1711477440402.png" alt="bramhani_9-1711477440402.png" /></span></P><P>Enter First name and last name and then save it.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_10-1711477470527.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86927i46D3C3750E83F7BD/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_10-1711477470527.png" alt="bramhani_10-1711477470527.png" /></span></P><P>Message has been sent to Event Mesh.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_11-1711477705205.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86929iE0711F544C6161C3/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_11-1711477705205.png" alt="bramhani_11-1711477705205.png" /></span></P><P>Check the payload after consuming the message in CPI by integration team.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_12-1711477855623.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86931iCC6780B78A7A4A84/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_12-1711477855623.png" alt="bramhani_12-1711477855623.png" /></span></P><P>Message number decreased to zero in Event Mesh after consuming the message in CPI.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bramhani_13-1711477967113.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/86933iDD26774AAA460556/image-size/medium?v=v2&amp;px=400" role="button" title="bramhani_13-1711477967113.png" alt="bramhani_13-1711477967113.png" /></span></P><P>Happy to hear the feedback&nbsp;<span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span></P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2024-03-27T10:04:35.331000+01:00 https://community.sap.com/t5/technology-blogs-by-members/upload-excel-using-sap-rap-only/ba-p/13666565 Upload Excel using SAP RAP Only 2024-04-16T12:50:21.211000+02:00 Amit_Sharma https://community.sap.com/t5/user/viewprofilepage/user-id/1434841 <P>Develop an SAP RAP based App to upload excel (CSV) file just like you used to develop SE38 classical report.</P><P>We often get this requirement of developing a utility to create/update mass data for a BO such as Purchase Orders, Materials, Sales Orders etc. In S/4 HANA, the customer prefers to use SAP Fiori applications, rather than using the old classical reports. But can we develop a Fiori application to upload a file without involving using SAP UI5? Yes, we can.</P><P>Using the following annotations, we can attach any file to our BO in SAP RAP –</P><P><STRONG>@Semantics.largeObject</STRONG></P><P>The only constraint is that we would need a table holding the uploaded attachment large object. Let’s dive into the steps –</P><P>First, we will create database tables. We need to create two DB tables. The first table i.e. parent table will store the file attachment, and the second table i.e. child table will store the data from the uploaded file. In our scenario, we will be uploading and processing CSV file.</P><P>File table - ZSES_FILE_TABLE</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'User File Table' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zses_file_table { key client : abap.clnt not null; key end_user : uname not null; status : abap.char(1); attachment : xstringval; mimetype : abap.char(128); filename : abap.char(128); local_created_by : abp_creation_user; local_created_at : abp_creation_tstmpl; local_last_changed_by : abp_locinst_lastchange_user; local_last_changed_at : abp_locinst_lastchange_tstmpl; last_changed_at : abp_lastchange_tstmpl }</code></pre><P>&nbsp;</P><P>Excel data table - ZSES_DB</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Excel Data' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #ALLOWED define table zses_db { key mandt : mandt not null; key end_user : uname not null; key entrysheet : lblni not null; key ebeln : ebeln not null; key ebelp : ebelp not null; ext_number : lblne1; begdate : lzvon; enddate : lzbis; @Semantics.quantity.unitOfMeasure : 'zses_db.base_uom' quantity : mengev; base_uom : meins; fin_entry : final; error : boolean; error_message : char100; }</code></pre><P>&nbsp;</P><P>Now, let's create Interface views on top of the tables we just created.</P><P>For parent interface view, we create ZI_SES_PARENT.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Excel File Table' define root view entity zi_ses_parent as select from usr02 as _user left outer join zses_file_table as _ses_file on _user.bname = _ses_file.end_user composition [0..*] of zi_ses_excel_data as _ses_excel { key _user.bname as end_user, _ses_file.status as status, cast( case when _ses_file.filename is initial and _ses_file.status is initial then 'File Not Uploaded' when _ses_file.filename is not initial and _ses_file.status is initial then 'File Uploaded' when _ses_file.filename is initial then 'File Not Uploaded' when _ses_file.status is not initial then 'File Processed' else ' ' end as abap.char( 20 ) ) as FileStatus, cast( case when _ses_file.filename is initial and _ses_file.status is initial then '1' when _ses_file.filename is not initial and _ses_file.status is initial then '2' when _ses_file.filename is initial then '1' when _ses_file.status is not initial then '3' else ' ' end as abap.char( 1 ) ) as CriticalityStatus, cast( case when _ses_file.filename is not initial then ' ' else 'X' end as boolean preserving type ) as HideExcel, @Semantics.largeObject: { mimeType: 'MimeType', fileName: 'Filename', acceptableMimeTypes: [ 'text/csv' ], contentDispositionPreference: #INLINE } // This will store the File into our table _ses_file.attachment as Attachment, @Semantics.mimeType: true _ses_file.mimetype as MimeType, _ses_file.filename as Filename, @Semantics.user.createdBy: true _ses_file.local_created_by as Local_Created_By, @Semantics.systemDateTime.createdAt: true _ses_file.local_created_at as Local_Created_At, @Semantics.user.lastChangedBy: true _ses_file.local_last_changed_by as Local_Last_Changed_By, //local ETag field --&gt; OData ETag @Semantics.systemDateTime.localInstanceLastChangedAt: true _ses_file.local_last_changed_at as Local_Last_Changed_At, //total ETag field @Semantics.systemDateTime.lastChangedAt: true _ses_file.last_changed_at as Last_Changed_At, _ses_excel } where _user.bname = $session.user</code></pre><P>&nbsp;</P><P>Looks complicated? Let me explain -<BR /><BR />1. We select primary data from USR02 table and left outer join it with our parent table&nbsp;ZSES_FILE_TABLE, so that every user can use the app without worrying about locking. As this application serves as a utility for excel file upload, multiple users can use it simultaneously.<BR />2. FileStatus field is introduced to decorate the application and show state to the user whether the file is uploaded, processed or not.<BR /><BR />Then we create interface view of child entity as ZI_SES_EXCEL_DATA.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'SES_excel_data' @Metadata.allowExtensions: true define view entity zi_ses_excel_data as select from zses_db association to parent zi_ses_parent as _ses_file on $projection.end_user = _ses_file.end_user { key end_user as end_user, key zses_db.entrysheet as Entrysheet, key zses_db.ebeln as Ebeln, key zses_db.ebelp as Ebelp, zses_db.ext_number as Ext_Number, zses_db.begdate as Begdate, zses_db.enddate as Enddate, zses_db.quantity as Quantity, zses_db.base_uom as Base_Uom, zses_db.fin_entry as Fin_Entry, zses_db.error as Error, zses_db.error_message as Error_Message, _ses_file }</code></pre><P>&nbsp;</P><P>Now, let's go for consumption views. These are pretty straightforward.</P><P>For parent, we create ZC_SES_PARENT.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Consumption View for File' @AccessControl.authorizationCheck: #NOT_REQUIRED @Metadata.allowExtensions: true define root view entity zc_ses_parent provider contract transactional_query as projection on zi_ses_parent { key end_user, @EndUserText.label: 'Processing Status' FileStatus as status, Attachment, MimeType, Filename, Local_Created_By, Local_Created_At, Local_Last_Changed_By, @EndUserText.label: 'Last Action On' Local_Last_Changed_At, Last_Changed_At, CriticalityStatus, HideExcel, /* Associations */ _ses_excel : redirected to composition child zc_ses_excel }</code></pre><P>&nbsp;</P><P>For child, we create&nbsp;ZC_SES_EXCEL.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Consumption View for Ses Excel Data' @AccessControl.authorizationCheck: #NOT_REQUIRED @Metadata.allowExtensions: true define view entity zc_ses_excel as projection on zi_ses_excel_data { key end_user, key Entrysheet, key Ebeln, key Ebelp, Ext_Number, Begdate, Enddate, Quantity, Base_Uom, Fin_Entry, Error, Error_Message, /* Associations */ _ses_file : redirected to parent zc_ses_parent }</code></pre><P>&nbsp;</P><P>We then create Metadata Extensions for both of our consumption/projection views -</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE annotate entity zc_ses_parent with { @UI.facet: [ /* Header Fecets and Datapoints */ { purpose: #HEADER, id:'HDR_USER', type: #DATAPOINT_REFERENCE, position: 10, targetQualifier: 'end_user' }, { purpose: #HEADER, id:'HDR_FILE', type: #DATAPOINT_REFERENCE, position: 20, targetQualifier: 'Local_Last_Changed_At' }, { purpose: #HEADER, id:'HDR_STATUS', type: #DATAPOINT_REFERENCE, position: 30, targetQualifier: 'status' }, //**---- Body facets { label: 'File Information', id: 'Attachment', type: #COLLECTION, position: 10 }, { label: 'Invoice Details', id: 'Invoicedet', type: #IDENTIFICATION_REFERENCE, position: 10, parentId: 'File', purpose: #STANDARD }, { id: 'Upload', type: #FIELDGROUP_REFERENCE, position: 20 ,targetQualifier: 'Upload', parentId: 'Attachment', purpose: #STANDARD }, //** --- Excel data Facet ** { label: 'Excel Data', id: 'Data', type: #LINEITEM_REFERENCE, position: 30, targetElement: '_ses_excel', parentId: 'Attachment', purpose: #STANDARD } ]// , hidden: #(HideExcel) } ] @UI: { lineItem: [ { position: 10, importance: #HIGH , label: 'Person Responsible'} ] , identification: [ { position: 10 , label: 'Person Responsible' } ], // { type: #FOR_ACTION, dataAction: 'uploadExcelData', label: 'Validate and Show' } ] , dataPoint: { title: 'Responsible Person', targetValueElement: 'end_user' } } end_user; @UI: { lineItem: [ { position: 20, importance: #HIGH , label: 'Processing Status'} ] , identification: [ { position: 20 , label: 'Processing Status' } ] , dataPoint: { title: 'Processing Status', targetValueElement: 'status' ,criticality: 'CriticalityStatus' ,criticalityRepresentation: #WITHOUT_ICON} } status; @UI: { fieldGroup: [ { position: 50, qualifier: 'Upload' , label: 'Attachment'} ]} @UI: { identification: [ { position: 30 , label: 'File' } ] } Attachment; @UI.hidden: true MimeType; @UI.hidden: true Filename; @UI: { dataPoint:{ title: 'Last Action On', targetValueElement: 'Local_Last_Changed_At' } } Local_Last_Changed_At; }</code></pre><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE annotate entity zc_ses_excel with { @UI.facet: [{ id: 'SES', type: #FIELDGROUP_REFERENCE, purpose: #STANDARD, label: 'SES', targetQualifier: 'SESDetails' }] @UI.lineItem: [{ position: 1 }] end_user; @UI.lineItem: [{ position: 10 , label: 'SES Number', invocationGrouping: #ISOLATED }, { type: #FOR_ACTION, dataAction: 'createSES', label: 'Process SES' }] @UI.fieldGroup: [{ position: 10 , label: 'SES Number', qualifier: 'SESDetails' }] Entrysheet; @UI.lineItem: [{ position: 20 , label: 'PO' }] @UI.fieldGroup: [{ position: 20 , label: 'PO', qualifier: 'SESDetails' }] Ebeln; @UI.lineItem: [{ position: 30 , label: 'PO Item' }] @UI.fieldGroup: [{ position: 30 , label: 'PO Item', qualifier: 'SESDetails' }] Ebelp; @UI.lineItem: [{ position: 40 , label: 'SES Name' }] @UI.fieldGroup: [{ position: 40 , label: 'SES Name', qualifier: 'SESDetails' }] Ext_Number; @UI.lineItem: [{ position: 50 , label: 'Valid From' }] @UI.fieldGroup: [{ position: 50 , label: 'Valid From', qualifier: 'SESDetails' }] Begdate; @UI.lineItem: [{ position: 60 , label: 'Valid To' }] @UI.fieldGroup: [{ position: 60 , label: 'Valid To', qualifier: 'SESDetails' }] Enddate; @UI.lineItem: [{ position: 70 , label: 'Quantity' }] @UI.fieldGroup: [{ position: 70 , label: 'Quantity', qualifier: 'SESDetails' }] Quantity; @UI.lineItem: [{ position: 80 , label: 'UOM' }] @UI.fieldGroup: [{ position: 80 , label: 'UOM', qualifier: 'SESDetails' }] Base_Uom; @UI.lineItem: [{ position: 90 , label: 'Final Entry' }] @UI.fieldGroup: [{ position: 90 , label: 'Final Entry', qualifier: 'SESDetails' }] Fin_Entry; @UI.lineItem: [{ position: 100 , label: 'Error' , hidden: true}] @UI.fieldGroup: [{ position: 100 , label: 'Error' , hidden: true}] Error; @UI.lineItem: [{ position: 110 , label: 'Error Message' }] @UI.fieldGroup: [{ position: 110 , label: 'Error Message', qualifier: 'SESDetails' }] Error_Message; }</code></pre><P>&nbsp;</P><P>Now, we create behavior definition ZI_SES_PARENT -</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_i_ses_parent unique; strict ( 2 ); with draft; define behavior for zi_ses_parent alias File persistent table zses_file_table lock master total etag end_user draft table zses_file_tabled authorization master ( instance ) etag master end_user { create; update; delete; // Logic to convert uploaded excel into internal table and save to the child entity is written here action ( features : instance ) uploadExcelData result [1] $self; association _ses_excel { create; with draft; } // Logic to trigger action uploadExcelData determination fields on modify { field Filename ; } draft action Edit ; draft action Activate; draft action Discard; draft action Resume; draft determine action Prepare ; } define behavior for zi_ses_excel_data alias ExcelData persistent table ZSES_DB lock dependent by _ses_file draft table zses_dbd authorization dependent by _ses_file etag master Begdate { update; delete; field ( readonly ) end_user; association _ses_file { with draft; } // Logic to process the uploaded data from excel action createSES result [1] $self; }</code></pre><P>And the behavior projection ZC_SES_PARENT -&nbsp;</P><pre class="lia-code-sample language-abap"><code>projection; strict ( 2 ); use draft; define behavior for zc_ses_parent //alias &lt;alias_name&gt; { use update; use delete; field ( readonly ) status , Local_Last_Changed_At ; use action Edit; use action Activate; use action Discard; use action Resume; use action Prepare; use association _ses_excel { create; with draft; } } define behavior for zc_ses_excel //alias &lt;alias_name&gt; { use update; use delete; use association _ses_file { with draft; } use action createSES; }</code></pre><P>&nbsp;</P><P>Now, in the behavior implementation class -&nbsp;ZBP_I_SES_PARENT, we have two important methods -</P><P><STRONG><U>Determination method - 'Fields' -&nbsp;</U></STRONG></P><pre class="lia-code-sample language-abap"><code>METHOD fields. SELECT <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/2449">@abap_true</a> INTO <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(lv_valid) FROM zses_file_table UP TO 1 ROWS WHERE end_user = <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/4244">@SY</a>-uname. ENDSELECT. IF lv_valid &lt;&gt; abap_true. INSERT zses_file_table FROM @( VALUE #( end_user = sy-uname ) ). ENDIF. MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file UPDATE FROM VALUE #( FOR key IN keys ( end_user = key-end_user status = ' ' " Accepted %control-status = if_abap_behv=&gt;mk-on ) ). IF keys[ 1 ]-%is_draft = '01'. MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file EXECUTE uploadexceldata FROM CORRESPONDING #( keys ). ENDIF. ENDMETHOD.</code></pre><P>Explanation:<BR />1. We save an entry with our username to the parent table, so that the once an instance is created and it goes inside the draft, it finds an instance to edit.<BR />2. We call the action&nbsp;<SPAN><STRONG>uploadexceldata</STRONG> such that whenever a new file is uploaded, it converts the data and store it into the child table.</SPAN></P><P><U><STRONG>Action method 'uploadExcelData' -</STRONG></U></P><pre class="lia-code-sample language-abap"><code> READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_inv). DATA(lv_attachment) = lt_inv[ 1 ]-attachment. DATA: rows TYPE STANDARD TABLE OF string, content TYPE string, conv TYPE REF TO cl_abap_conv_in_ce, ls_excel_data TYPE zses_db, lt_excel_data TYPE STANDARD TABLE OF zses_db, lv_quantity TYPE char10, lv_entrysheet TYPE ebeln. conv = cl_abap_conv_in_ce=&gt;create( input = lv_attachment ). conv-&gt;read( IMPORTING data = content ). SPLIT content AT cl_abap_char_utilities=&gt;cr_lf INTO TABLE rows. LOOP AT rows INTO DATA(ls_row). SPLIT ls_row AT ',' INTO ls_excel_data-entrysheet ls_excel_data-ebeln ls_excel_data-ebelp ls_excel_data-ext_number ls_excel_data-begdate ls_excel_data-enddate lv_quantity "ls_attdata-BASE_UOM ls_excel_data-fin_entry. ls_excel_data-entrysheet = lv_entrysheet = |{ ls_excel_data-entrysheet ALPHA = IN }|. ls_excel_data-ebeln = |{ ls_excel_data-ebeln ALPHA = IN }|. ls_excel_data-ebelp = |{ ls_excel_data-ebelp ALPHA = IN }|. ls_excel_data-quantity = CONV #( lv_quantity ). APPEND ls_excel_data TO lt_excel_data. CLEAR: ls_row, ls_excel_data. ENDLOOP.</code></pre><P>Explanation -<BR />1. Read the excel file (CSV in our case) from the entity and append it to internal table LT_EXCEL_DATA.<BR />2. Use EML to insert the data from LT_EXCEL_DATA to the child table.&nbsp;<BR /><BR />Please refer below code for the implementation class -</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS lhc_exceldata DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION IMPORTING keys REQUEST requested_authorizations FOR exceldata RESULT result. METHODS createses FOR MODIFY IMPORTING keys FOR ACTION exceldata~createses RESULT result. ENDCLASS. CLASS lhc_exceldata IMPLEMENTATION. METHOD get_instance_authorizations. ENDMETHOD. METHOD createses. READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY exceldata ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_data). DATA: ls_header_data TYPE i_serviceentrysheettp_2, ls_item_data TYPE i_serviceentrysheetitemtp_2, lt_header_crt TYPE TABLE FOR CREATE i_serviceentrysheettp_2\\serviceentrysheet, lt_item_cba TYPE TABLE FOR CREATE i_serviceentrysheettp_2\\serviceentrysheet\_serviceentrysheetitem. * Create SES with reference to a Service Purchase Order Item *--- Prepare Header Data ls_header_data-serviceentrysheetname = 'Demo SES'. ls_header_data-purchaseorder = `4500000286`. ls_header_data-sesoriginobjecttype = `EX`. *--- Prepare Item Data ls_item_data-purchaseorderitem = '00010'. ls_item_data-confirmedquantity = '1'. ls_item_data-accountassignmentcategory = 'K'. ls_item_data-serviceperformancedate = '20230207'. ls_item_data-multipleacctassgmtdistribution = '0'. *--- Prepare Payload APPEND INITIAL LINE TO lt_header_crt ASSIGNING FIELD-SYMBOL(&lt;ls_hdr_crt&gt;). &lt;ls_hdr_crt&gt; = CORRESPONDING #( ls_header_data CHANGING CONTROL ). &lt;ls_hdr_crt&gt;-%cid = `HEADER_1` . APPEND INITIAL LINE TO lt_item_cba ASSIGNING FIELD-SYMBOL(&lt;ls_itm_cba&gt;). &lt;ls_itm_cba&gt;-%cid_ref = 'HEADER_1'. APPEND INITIAL LINE TO &lt;ls_itm_cba&gt;-%target ASSIGNING FIELD-SYMBOL(&lt;item_data&gt;). &lt;item_data&gt; = CORRESPONDING #( ls_item_data CHANGING CONTROL ). &lt;item_data&gt;-%cid = 'Item_1'. MODIFY ENTITIES OF i_serviceentrysheettp_2 ENTITY serviceentrysheet CREATE FROM lt_header_crt CREATE BY \_serviceentrysheetitem FROM lt_item_cba FAILED DATA(ls_failed_crt) REPORTED DATA(ls_reported_crt) MAPPED DATA(ls_mapped_crt). ENDMETHOD. ENDCLASS. CLASS lhc_file DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION IMPORTING keys REQUEST requested_authorizations FOR file RESULT result. METHODS uploadexceldata FOR MODIFY IMPORTING keys FOR ACTION file~uploadexceldata RESULT result. METHODS fields FOR DETERMINE ON MODIFY IMPORTING keys FOR file~fields. METHODS get_instance_features FOR INSTANCE FEATURES IMPORTING keys REQUEST requested_features FOR file RESULT result. ENDCLASS. CLASS lhc_file IMPLEMENTATION. METHOD get_instance_authorizations. ENDMETHOD. METHOD uploadexceldata. ** Check if there exist an entry with current logged in username in parent table SELECT <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/2449">@abap_true</a> INTO <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(lv_valid) FROM zses_file_table UP TO 1 ROWS WHERE end_user = <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/4244">@SY</a>-uname. ENDSELECT. ** Create one entry, if it does not exist IF lv_valid &lt;&gt; abap_true. INSERT zses_file_table FROM @( VALUE #( end_user = sy-uname ) ). ENDIF. ** Read the parent instance READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_inv). ** Get attachment value from the instance DATA(lv_attachment) = lt_inv[ 1 ]-attachment. ** Data declarations DATA: rows TYPE STANDARD TABLE OF string, content TYPE string, conv TYPE REF TO cl_abap_conv_in_ce, ls_excel_data TYPE zses_db, lt_excel_data TYPE STANDARD TABLE OF zses_db, lv_quantity TYPE char10, lv_entrysheet TYPE ebeln. ** Convert excel file with CSV format into internal table of type string conv = cl_abap_conv_in_ce=&gt;create( input = lv_attachment ). conv-&gt;read( IMPORTING data = content ). ** Split the string table to rows SPLIT content AT cl_abap_char_utilities=&gt;cr_lf INTO TABLE rows. ** Process the rows and append to the internal table LOOP AT rows INTO DATA(ls_row). SPLIT ls_row AT ',' INTO ls_excel_data-entrysheet ls_excel_data-ebeln ls_excel_data-ebelp ls_excel_data-ext_number ls_excel_data-begdate ls_excel_data-enddate lv_quantity "ls_attdata-BASE_UOM ls_excel_data-fin_entry. ls_excel_data-entrysheet = lv_entrysheet = |{ ls_excel_data-entrysheet ALPHA = IN }|. ls_excel_data-ebeln = |{ ls_excel_data-ebeln ALPHA = IN }|. ls_excel_data-ebelp = |{ ls_excel_data-ebelp ALPHA = IN }|. ls_excel_data-quantity = CONV #( lv_quantity ). APPEND ls_excel_data TO lt_excel_data. CLEAR: ls_row, ls_excel_data. ENDLOOP. ** Delete duplicate records DELETE ADJACENT DUPLICATES FROM lt_excel_data. DELETE lt_excel_data WHERE ebeln IS INITIAL. ** Prepare the datatypes to store the data from internal table lt_excel_data to child entity through EML DATA lt_att_create TYPE TABLE FOR CREATE zi_ses_parent\_ses_excel. lt_att_create = VALUE #( ( %cid_ref = keys[ 1 ]-%cid_ref %is_draft = keys[ 1 ]-%is_draft end_user = keys[ 1 ]-end_user %target = VALUE #( FOR ls_data IN lt_excel_data ( %cid = |{ ls_data-ebeln }{ ls_data-ebelp }| %is_draft = keys[ 1 ]-%is_draft end_user = sy-uname entrysheet = ls_data-entrysheet ebeln = ls_data-ebeln ebelp = ls_data-ebelp ext_number = ls_data-ext_number begdate = ls_data-begdate enddate = ls_data-enddate quantity = ls_data-quantity " BASE_UOM = ls_data- fin_entry = ls_data-fin_entry %control = VALUE #( end_user = if_abap_behv=&gt;mk-on entrysheet = if_abap_behv=&gt;mk-on ebeln = if_abap_behv=&gt;mk-on ebelp = if_abap_behv=&gt;mk-on ext_number = if_abap_behv=&gt;mk-on begdate = if_abap_behv=&gt;mk-on enddate = if_abap_behv=&gt;mk-on quantity = if_abap_behv=&gt;mk-on " BASE_UOM = ls_data- fin_entry = if_abap_behv=&gt;mk-on ) ) ) ) ). READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file BY \_ses_excel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_excel). ** Delete already existing entries from child entity MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY exceldata DELETE FROM VALUE #( FOR ls_excel IN lt_excel ( %is_draft = ls_excel-%is_draft %key = ls_excel-%key ) ) MAPPED DATA(lt_mapped_delete) REPORTED DATA(lt_reported_delete) FAILED DATA(lt_failed_delete). ** Create the records from the new attached CSV file MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file CREATE BY \_ses_excel AUTO FILL CID WITH lt_att_create. APPEND VALUE #( %tky = lt_inv[ 1 ]-%tky ) TO mapped-file. APPEND VALUE #( %tky = lt_inv[ 1 ]-%tky %msg = new_message_with_text( severity = if_abap_behv_message=&gt;severity-success text = 'Excel Data Uploaded' ) ) TO reported-file. MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file UPDATE FROM VALUE #( ( %is_draft = keys[ 1 ]-%is_draft end_user = sy-uname status = 'P' " %data = VALUE #( status = 'P' ) %control = VALUE #( status = if_abap_behv=&gt;mk-on ) ) ) MAPPED DATA(lt_mapped_update) REPORTED DATA(lt_reported_update) FAILED DATA(lt_failed_update). READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_file_status). MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file UPDATE FROM VALUE #( FOR ls_file_status IN lt_file_status ( %is_draft = ls_file_status-%is_draft %tky = ls_file_status-%tky %data = VALUE #( status = 'C' ) %control = VALUE #( status = if_abap_behv=&gt;mk-on ) ) ). READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_file). result = VALUE #( FOR ls_file IN lt_file ( %tky = ls_file-%tky %param = ls_file ) ). ENDMETHOD. METHOD fields. SELECT <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/2449">@abap_true</a> INTO <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(lv_valid) FROM zses_file_table UP TO 1 ROWS WHERE end_user = <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/4244">@SY</a>-uname. ENDSELECT. IF lv_valid &lt;&gt; abap_true. INSERT zses_file_table FROM @( VALUE #( end_user = sy-uname ) ). ENDIF. MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file UPDATE FROM VALUE #( FOR key IN keys ( end_user = key-end_user status = ' ' " Accepted %control-status = if_abap_behv=&gt;mk-on ) ). IF keys[ 1 ]-%is_draft = '01'. MODIFY ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file EXECUTE uploadexceldata FROM CORRESPONDING #( keys ). ENDIF. ENDMETHOD. METHOD get_instance_features. READ ENTITIES OF zi_ses_parent IN LOCAL MODE ENTITY file FIELDS ( end_user ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_file). result = VALUE #( FOR ls_file IN lt_file ( %key = ls_file-%key %is_draft = ls_file-%is_draft %features-%action-uploadexceldata = COND #( WHEN ls_file-%is_draft = '00' THEN if_abap_behv=&gt;fc-f-read_only ELSE if_abap_behv=&gt;fc-f-unrestricted ) ) ). ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>After this, create service definition, expose both the parent and child consumption views, create a service binding and see the wonders.<BR />The list report page would look like -&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Amit_Sharma_0-1712825902783.png" style="width: 653px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/95000iA5FC1C16D999EE71/image-dimensions/653x178?v=v2" width="653" height="178" role="button" title="Amit_Sharma_0-1712825902783.png" alt="Amit_Sharma_0-1712825902783.png" /></span></P><P>Since, we used where clause to filter the parent records based on the current logged-in user in the interface view ZI_SES_PARENT, we should see only 1 record here. You can also skip the list report page in SAP BAS and deploy the app which directly opens the object page.&nbsp;<BR />When navigate to the object page and click on edit.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Amit_Sharma_1-1712826078742.png" style="width: 675px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/95001i854176227A912408/image-dimensions/675x324?v=v2" width="675" height="324" role="button" title="Amit_Sharma_1-1712826078742.png" alt="Amit_Sharma_1-1712826078742.png" /></span></P><P>Once saved, we should see the records -</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Amit_Sharma_2-1712826242815.png" style="width: 673px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/95002i217919ACED4CC839/image-dimensions/673x330?v=v2" width="673" height="330" role="button" title="Amit_Sharma_2-1712826242815.png" alt="Amit_Sharma_2-1712826242815.png" /></span></P><P>You can write the logic to process these records in an instance action for child entity, just like we have an action defined as 'Process SES'.<BR />With this process, you can upload CSV file and process the records. You can try changing the logic to process XSLX file as well.&nbsp;<BR /><BR /></P> 2024-04-16T12:50:21.211000+02:00 https://community.sap.com/t5/application-development-blog-posts/writing-unveiling-abap-unit-tests-for-table-functions/ba-p/13669290 Writing/Unveiling ABAP Unit Tests for Table Functions 2024-04-16T13:01:57.878000+02:00 kishore_kumar_g https://community.sap.com/t5/user/viewprofilepage/user-id/1438038 <P style=" text-align : left; "><STRONG>Introduction</STRONG></P><P><EM>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; In SAP ABAP development, writing robust code is essential for ensuring the stability and reliability of applications. One powerful tool for achieving this is the ABAP Unit, which allows developers to automate the testing process and validate the behavior of their code. In this blog post, we will explore how to write ABAP unit tests specifically for table functions.</EM></P><P><STRONG><EM>ABAP CDS - Table Functions</EM></STRONG></P><P><EM>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A CDS table function is defined in the&nbsp;DDL source code&nbsp;of a&nbsp;CDS data definition&nbsp;in the&nbsp;ABAP development tools for Eclipse&nbsp;using the statement&nbsp;<STRONG>DEFINE TABLE FUNCTION</STRONG>&nbsp;in the&nbsp;CDS DDL&nbsp;of the&nbsp;ABAP Core Data Services (CDS). A CDS table function includes the following (including an example that is included later in the blog):</EM></P><UL><LI><EM>The&nbsp;CDS entity (e.g., ZFLIGHTS )</EM></LI><LI><EM>An&nbsp;AMDP function implementation ( e.g.,&nbsp;<SPAN>ZCL_FLIGHT_DETAILS )</SPAN></EM></LI></UL><P><EM><SPAN>Here, we'll use a classic example of SFLIGHT data to illustrate the creation of the query within the table function.</SPAN></EM></P><P>- Table Function CDS Entity:</P><P style=" padding-left : 30px; "><SPAN>The following is the table function, equipped with a parameter to facilitate filtering during selection.</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Flights and its Details' @ClientHandling.algorithm: #SESSION_VARIABLE @ClientHandling.type: #CLIENT_DEPENDENT define table function ZFLIGHTS with parameters @Environment.systemField: #CLIENT P_mandt : abap.clnt, P_CarrierId : s_carr_id returns { key mandt : abap.clnt; key carrierId : s_carr_id; key connectionId : s_conn_id; key flightDate : s_date; name : s_carrname; planeType : s_planetye; seatsMax : s_seatsmax; currencyCode : s_currcode; } implemented by method ZCL_FLIGHT_DETAILS=&gt;get_details;</code></pre><P>&nbsp;</P><P><EM>- Implementation of the table AMDP function is&nbsp; below:</EM></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS zcl_flight_details DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. CLASS-METHODS get_details FOR TABLE FUNCTION zflights. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_flight_details IMPLEMENTATION. METHOD get_details BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING s_flights s_carrier. RETURN select _flight.mandt, _flight.CarrierId, _flight.ConnectionId, _flight.FlightDate, _carrier.Name, _flight.planetype, _flight.seatsmax, _flight.currencyCode from s_flights as _flight left outer join s_carrier as _carrier on _flight.mandt = _carrier.mandt and _flight.CarrierId = _carrier.CarrierId where _flight.mandt = :P_mandt and _flight.CarrierId = :P_CarrierId; ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P>&nbsp;</P><P><EM><STRONG>Setting Up an ABAP Unit Environment</STRONG></EM></P><P><EM>&nbsp; &nbsp; &nbsp; &nbsp;Before crafting tests for table functions, it is imperative to establish the ABAP unit environment. This process entails crafting a test class along with methods to assess the functionality of the table function. Let's initiate the creation of a class named <FONT color="#FF9900">ZCL_AUNIT_ZFLIGHTS</FONT>, within which we'll create a local test class termed <FONT color="#FF9900">LCL_CL_AUNIT_ZFLIGHTS</FONT><STRONG><FONT color="#FF9900"><FONT color="#000000">.</FONT></FONT></STRONG></EM></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS lcl_cl_aunit_zflights DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PUBLIC SECTION. CLASS-DATA: environment TYPE REF TO if_amdp_test_environment. PRIVATE SECTION. CLASS-METHODS class_setup. CLASS-METHODS class_teardown. METHODS setup. ENDCLASS. CLASS lcl_cl_aunit_zflights IMPLEMENTATION. METHOD class_setup. " For testing an AMDP table function which is a CDS table function source, " 1. One would need to configure the AMDP table function class and the method name in the AMDP test configuration step. " Here the AMDP method 'ZCL_FLIGHT_DETAILS=&gt;GET_DETAILS' is a table function which is used as a source for the CDS table function 'CDSFRWK_TF_FLIGHT_BOOKING'. DATA(environment_config) = cl_amdp_test_environment=&gt;create_test_configuration( ). environment_config-&gt;add_amdp_class( 'ZCL_FLIGHT_DETAILS' )-&gt;add_methods_for_unit_test( VALUE #( ( 'GET_DETAILS' ) ) ). environment = cl_amdp_test_environment=&gt;create( environment_config ). ENDMETHOD. METHOD class_teardown. IF environment IS NOT INITIAL. environment-&gt;destroy( ). ENDIF. ENDMETHOD. METHOD setup. " Clears any existing test configuration on the test doubles which are set by other unit test methods. environment-&gt;clear_doubles( ). ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P><P><EM>In the method class_setup, the environment configuration is done, in which the name of the AMDP class and its method to be tested need to be given.</EM></P><P>&nbsp;</P><P><EM><STRONG>Mocking Data</STRONG></EM></P><P><EM>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For mocking data, we'll create a new method named test_cds_table_function within the private section of the test class. This method will facilitate the generation of mock data for testing purposes.</EM></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>PRIVATE SECTION. METHODS test_cds_table_function FOR TESTING RAISING cx_static_check.</code></pre><P>&nbsp;</P><P><EM>By default, if no client is specified, the system client will be assumed. Since I aim to demonstrate data mocking at the client level, I'll simulate data for two distinct clients and execute the query with client-specific information.</EM></P><P><EM>&nbsp; - Procedure to mock the data:</EM></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>"To get the object instance of the dependency used in the AMDP Implementation Class DATA(lo_object) = environment-&gt;get_test_double( DEPENDENCY ). "Set the client for which the data is being mocked lo_object-&gt;get_view_content_config( )-&gt;for_client( CLIENT-INFO ). "Set the content of the dependency lo_object-&gt;get_view_content_config( )-&gt;set_content( CONTENT ).</code></pre><P>&nbsp;</P><P><EM>The actual Implementation of the method is below:</EM></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code> METHOD test_cds_table_function. DATA: lt_flights_001 TYPE STANDARD TABLE OF s_flights, lt_flights_714 TYPE STANDARD TABLE OF s_flights, lt_carrier_001 TYPE STANDARD TABLE OF s_carrier, lt_carrier_714 type standard table of s_carrier. lt_flights_001 = VALUE #( ( CarrierId = 'AA' ConnectionId = '0101' FlightDate = '20240101' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ( CarrierId = 'DL' ConnectionId = '0102' FlightDate = '20240201' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ( CarrierId = 'DL' ConnectionId = '0103' FlightDate = '20240301' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ). lt_carrier_001 = VALUE #( ( carrierid = 'AA' Name = 'American Airlines' ) ( carrierid = 'DL' Name = 'Delta Airlines' ) ). lt_flights_714 = VALUE #( ( CarrierId = 'AA' ConnectionId = '0104' FlightDate = '20240401' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ( CarrierId = 'DL' ConnectionId = '0105' FlightDate = '20240501' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ( CarrierId = 'DL' ConnectionId = '0106' FlightDate = '20240601' planetype = 'A340-600' seatsmax = '330' currencycode = 'USD' ) ). lt_carrier_714 = VALUE #( ( carrierid = 'AA' Name = 'American Airlines' ) ( carrierid = 'DL' Name = 'Delta Airlines' ) ). " Get the test double of "S_FLIGHTS" &amp; "S_CARRIER" from the test environment. DATA(lo_flight) = environment-&gt;get_test_double( 'S_FLIGHTS' ). DATA(lo_carrier) = environment-&gt;get_test_double( 'S_CARRIER' ). lo_flight-&gt;get_view_content_config( )-&gt;for_client( '001' ). lo_carrier-&gt;get_view_content_config( )-&gt;for_client( '001' ). lo_flight-&gt;get_view_content_config( )-&gt;set_content( lt_flights_001 ). lo_carrier-&gt;get_view_content_config( )-&gt;set_content( lt_carrier_001 ). lo_flight-&gt;get_view_content_config( )-&gt;for_client( '714' ). lo_carrier-&gt;get_view_content_config( )-&gt;for_client( '714' ). lo_flight-&gt;get_view_content_config( )-&gt;set_content( lt_flights_714 ). lo_carrier-&gt;get_view_content_config( )-&gt;set_content( lt_carrier_714 ). SELECT * FROM zflights( p_carrierid = 'DL' ) USING CLIENT '714' INTO TABLE (lt_result). cl_abap_unit_assert=&gt;assert_equals( EXPORTING act = lines( lt_result ) " Data object with current value exp = 2 " Data object with expected type ). ENDMETHOD.</code></pre><P>&nbsp;</P><P>&nbsp;</P><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><P>&nbsp;</P><P><EM>While executing the query for client '714', <FONT color="#FF9900">LT_RESULT</FONT> acquired the following records. The assertion verifies the successful retrieval of 2 records for client '714'.</EM></P><P>&nbsp;</P><P>&nbsp;</P></DIV></DIV></DIV><DIV class=""><DIV class=""><span class="lia-inline-image-display-wrapper lia-image-align-left" image-alt="Output.jpg" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/96052i8B7038EB56273B35/image-size/medium?v=v2&amp;px=400" role="button" title="Output.jpg" alt="Output.jpg" /></span></DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class="">&nbsp;</DIV><DIV class=""><EM><STRONG>Conclusion</STRONG></EM></DIV><DIV class=""><EM>Writing ABAP unit tests holds significant importance in SAP ABAP development.&nbsp;Thorough testing not only confirms the accuracy of table functions but also enhances the overall stability and performance of the system.&nbsp;</EM></DIV><DIV class="">&nbsp;</DIV><DIV class=""><EM>Happy Coding&nbsp;<span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span></EM></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV> 2024-04-16T13:01:57.878000+02:00 https://community.sap.com/t5/application-development-blog-posts/consume-restful-webservices-using-post-man/ba-p/13674961 Consume Restful Webservices using POST MAN 2024-04-19T15:56:31.284000+02:00 Narasimha_Sesti https://community.sap.com/t5/user/viewprofilepage/user-id/169013 <P>HTTP-based APIs integrate easily with RESTful web services. There are many ways to use HTTP methods to consume and update and retrieve&nbsp; these API data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_5-1713445164735.jpeg" style="width: 346px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98181i35EFB49511605861/image-dimensions/346x329?v=v2" width="346" height="329" role="button" title="Narasimha_Sesti_5-1713445164735.jpeg" alt="Narasimha_Sesti_5-1713445164735.jpeg" /></span></P><P>HTTP API methods and understand how to use them appropriately on resources</P><P><STRONG>Method 1: GET</STRONG></P><P>The most common HTTP method is GET, which returns a representational view of a resource's contents and data. GET should be used in read-only mode, which keeps the data safe, You should get the same results no matter how many times you use this method, unless it is modified by another client in the interim.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_16-1713446097628.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98210iC3CD233A5F51F22F/image-size/large?v=v2&amp;px=999" role="button" title="Narasimha_Sesti_16-1713446097628.png" alt="Narasimha_Sesti_16-1713446097628.png" /></span></P><P><STRONG>Method 2: POST</STRONG></P><P>Post request used to create resource (Record ) in server, While creating record we have to pass Body data Parameters(key, values) to create the Record as JSON, <STRONG>Form</STRONG> formats are supported.</P><P>&nbsp;</P><P>&nbsp;<span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_17-1713446242193.png" style="width: 744px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98228iF60BE263AACC5C88/image-dimensions/744x374?v=v2" width="744" height="374" role="button" title="Narasimha_Sesti_17-1713446242193.png" alt="Narasimha_Sesti_17-1713446242193.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_26-1713448773787.png" style="width: 665px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98282iB57D135E93A5883A/image-dimensions/665x336?v=v2" width="665" height="336" role="button" title="Narasimha_Sesti_26-1713448773787.png" alt="Narasimha_Sesti_26-1713448773787.png" /></span></P><P>While submitting the data we have to update <STRONG>Header&nbsp;</STRONG>tab <STRONG>content type</STRONG> with <STRONG>application/JSON</STRONG>.</P><P>After create new record by using browser you&nbsp; will received updated data. By default Browsers using HTTP Protocol with GET method to retrieve data from service.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_18-1713446586084.png" style="width: 672px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98245iF7E7E1C61155DBA5/image-dimensions/672x351?v=v2" width="672" height="351" role="button" title="Narasimha_Sesti_18-1713446586084.png" alt="Narasimha_Sesti_18-1713446586084.png" /></span></P><P><STRONG>Method 3: PATCH</STRONG></P><P>PATCH is another HTTP method used to update resources. As opposed to replacing resources, like the PUT method does, PATCH only modifies resource contents. As a general rule, these modifications worked based on Key.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_19-1713446858588.png" style="width: 728px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98248iB8B97E1D86EBA46E/image-dimensions/728x383?v=v2" width="728" height="383" role="button" title="Narasimha_Sesti_19-1713446858588.png" alt="Narasimha_Sesti_19-1713446858588.png" /></span></P><P>While submitting the data we have to update <STRONG>Header&nbsp;</STRONG>tab <STRONG>content type</STRONG> with <STRONG>application/JSON</STRONG>.</P><P>Patch update the record based on Id, after update you will find latest records by refresh your browser.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_21-1713447375169.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98257iEB9232BD3C57A48C/image-size/medium?v=v2&amp;px=400" role="button" title="Narasimha_Sesti_21-1713447375169.png" alt="Narasimha_Sesti_21-1713447375169.png" /></span></P><P>We have create additional record 4 for other operations in above list.</P><P><STRONG>Method 5: DELETE</STRONG></P><P>The last HTTP method DELETE. When a DELETE method targets a single resource, that resource is removed entirely(Hard Delete). we have to pass based on Key ID (4).</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_22-1713447488529.png" style="width: 721px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98259i6B207E0BC8840A82/image-dimensions/721x376?v=v2" width="721" height="376" role="button" title="Narasimha_Sesti_22-1713447488529.png" alt="Narasimha_Sesti_22-1713447488529.png" /></span></P><P>Delete Method will delete the 4th record based on Key. after we can refresh browser data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_23-1713447561137.png" style="width: 660px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98260i7AF2219A1C58061E/image-dimensions/660x416?v=v2" width="660" height="416" role="button" title="Narasimha_Sesti_23-1713447561137.png" alt="Narasimha_Sesti_23-1713447561137.png" /></span></P><P><STRONG>Authentication</STRONG></P><P>Authentication tab help to protect the API data using different security ways.</P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_24-1713447959184.png" style="width: 551px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98265iE8DB8E370885E2B5/image-dimensions/551x354?v=v2" width="551" height="354" role="button" title="Narasimha_Sesti_24-1713447959184.png" alt="Narasimha_Sesti_24-1713447959184.png" /></span></P><P>&nbsp;</P><H2 id="toc-hId-992590019">Basic Authentication</H2><P><STRONG>Basic Authentication is a method of securing HTTP requests through a special header</STRONG>:</P><H2 id="toc-hId-796076514">Authorization Tab</H2><P>let’s send a GET request to a Basic Auth-secured endpoint and expect an&nbsp;<EM>Unauthorized</EM>&nbsp;status for the response:</P><P>Now, let’s add the credentials. To do this,&nbsp;<STRONG>we simply go to the “</STRONG><EM><STRONG>Authorization</STRONG></EM><STRONG>” tab and select “</STRONG><EM><STRONG>Basic Auth</STRONG></EM><STRONG>” as the authorization type</STRONG>. After that, we insert the username and password and we’re all set:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_25-1713448188952.png" style="width: 726px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98274i9D0F299688A06FC9/image-dimensions/726x212?v=v2" width="726" height="212" role="button" title="Narasimha_Sesti_25-1713448188952.png" alt="Narasimha_Sesti_25-1713448188952.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P><SPAN><STRONG>2) Authorization</STRONG></SPAN><SPAN>: </SPAN>Basic &lt;credentials&gt;</P><P>To generate the credentials token, we need to write the username and password, joined by the semicolon character. After that, we need to encode the resulting string with Base64.</P><P style=" text-align : justify; ">Let’s assume the username is “<EM>admin</EM>” and the password is “<EM>baeldung</EM>“. First, we’ll create the credentials string, which will be “<EM>admin:baeldung</EM>“. Then, we’ll encode it with Base64, add the “<EM>Basic</EM>” keyword, and set it as the <STRONG>header’s</STRONG> value:</P><H2 id="toc-hId-599563009">&nbsp;</H2><H3 id="toc-hId-532132223"><STRONG>What is Bearer Authentication?</STRONG></H3><P style=" text-align : justify; ">HTTP provides a framework for controlling access to protected resources. HTTP authentication&nbsp;is performed by sending authentication credentials in the authorization header to access the protected resource. Bearer authentication (also called token authentication) is one of the HTTP authentication schemes that grant access to the bearer of this token. Bearer token authentication is done by sending a security token with every HTTP request we make to the server. You can do bearer authentication with any programming language.</P><P><STRONG>Bearer Token Authentication Syntax</STRONG></P><P>Authorization: Bearer {token}</P><H1 id="toc-hId-77453280"><SPAN>&nbsp;Postman displays the response data sent from the server in the lower pane.</SPAN></H1><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Narasimha_Sesti_4-1713445164731.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98183i2C05037925C601A8/image-size/medium?v=v2&amp;px=400" role="button" title="Narasimha_Sesti_4-1713445164731.png" alt="Narasimha_Sesti_4-1713445164731.png" /></span></P> 2024-04-19T15:56:31.284000+02:00 https://community.sap.com/t5/technology-blogs-by-sap/exploring-graphql-and-rest-for-sap-developers/ba-p/13681247 Exploring GraphQL and REST for SAP Developers 2024-04-26T14:10:06.068000+02:00 Marwah_Shwaiki https://community.sap.com/t5/user/viewprofilepage/user-id/7391 <P>I came across GraphQL while working on a side project and as a SAP Developer who worked a lot with REST APIs, I was wondering what advantages GraphQL could offer me, and how to apply it for different use cases. So, I decided to explore both APIs and how to use them in the SAP context. Here is a brief overview of my thoughts about both APIs.</P><P><STRONG>Introduction</STRONG></P><P>let's start with a brief definition of the APIs concept, APIs are the lifeblood of modern software development, bridging the gap between different systems. They define rules for accessing functionality and data remotely. Let's delve into API concepts and see how GraphQL and REST fit into the SAP world.</P><P>Over the past decade, REST has been the go-to for web APIs, but it's not without its flaws. Enter GraphQL, developed to tackle the shortcomings of REST and provide more flexibility and efficiency for developers.</P><P><STRONG>Understanding APIs:</STRONG> APIs act as intermediaries facilitating communication between software applications. They come in two main flavors: SOAP, known for its strict standards, and REST, favored for its simplicity and scalability.</P><P><STRONG>GraphQL:</STRONG> GraphQL, developed by Facebook, offers a more powerful alternative to REST. It allows clients to request specific data, reducing over-fetching issues common in REST APIs.</P><P><STRONG>REST:</STRONG> REST, an architectural style for building networked applications, relies on stateless, client-server communication via HTTP.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="6d0omhgylpa6e584fqot.jpg" style="width: 566px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/101281i6D79EE1E4F1D1BD7/image-size/large?v=v2&amp;px=999" role="button" title="6d0omhgylpa6e584fqot.jpg" alt="6d0omhgylpa6e584fqot.jpg" /></span></P><P>&nbsp;</P><H3 id="toc-hId-1122500103"><STRONG>Key Differences</STRONG></H3><OL><LI><STRONG>Data Fetching:</STRONG> GraphQL enables precise data fetching with a single request, unlike REST which may lead to over-fetching or under-fetching.</LI><LI><STRONG>Endpoint Complexity:</STRONG> REST APIs often require multiple endpoints, while GraphQL offers a single endpoint handling various data requests.</LI><LI><STRONG>Versioning:</STRONG> REST commonly relies on versioning, unlike GraphQL which allows backward-compatible changes without versioning.</LI><LI><STRONG>Caching:</STRONG> REST APIs leverage HTTP caching mechanisms, while GraphQL responses typically require additional configuration for caching.</LI></OL><H2 id="toc-hId-796903879"><STRONG>Similarities</STRONG></H2><P>Both GraphQL and REST facilitate data exchange between services or applications, following a client-server model.</P><H3 id="toc-hId-729473093"><STRONG>Architecture</STRONG></H3><UL><LI>Both are stateless and use a client-server model based on HTTP.</LI></UL><H3 id="toc-hId-532959588"><STRONG>Resource-based Design</STRONG></H3><P>Both REST and GraphQL design data interchange around resources, each with its unique identifier and set of operations.</P><H3 id="toc-hId-336446083"><STRONG>Data Exchange</STRONG></H3><P>Both support JSON as the primary data exchange format and caching for improved performance.</P><H2 id="toc-hId-10849859"><STRONG>When to Use What?</STRONG></H2><P><STRONG>Use REST When:</STRONG></P><UL><LI>You need a straightforward and widely adopted solution.</LI><LI>Your data requirements are consistent and well-defined.</LI><LI>Caching is crucial for your application's performance.</LI><LI>You're working with legacy systems that are compatible with REST.</LI></UL><P><STRONG>Use GraphQL When:</STRONG></P><UL><LI>Your data requirements are dynamic and vary across different clients.</LI><LI>Over-fetching or under-fetching of data is a concern.</LI><LI>You want to reduce the number of API calls and improve efficiency.</LI><LI>You're developing a new application or service and want flexibility in data retrieval.</LI></UL><H3 id="toc-hId--56580927"><STRONG>Conclusion</STRONG></H3><P>GraphQL and REST are vital for integration and data exchange in the SAP ecosystem. While REST is popular for its simplicity, GraphQL's flexibility is gaining traction. Understanding their nuances empowers SAP developers to design effective APIs for their solutions.</P><P><!-- notionvc: 029c7c77-dc17-463a-acc4-5b13f32d69f4 --></P> 2024-04-26T14:10:06.068000+02:00