https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/ABAP-Development-blog-posts.xml SAP Community - ABAP Development 2025-07-09T11:00:04.285670+00:00 python-feedgen ABAP Development blog posts in SAP Community https://community.sap.com/t5/application-development-and-automation-blog-posts/setup-your-btp-trial-account-and-abap-environment/ba-p/14131685 Setup your BTP Trial account and ABAP environment 2025-06-19T14:56:53.611000+02:00 SangeetaSingh https://community.sap.com/t5/user/viewprofilepage/user-id/747879 <P>Hi Community,&nbsp;</P><P>Here are the steps to create your first BTP trial account and setup ABAP on cloud environment in eclipse.&nbsp;</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">1. <EM>Create an account on SAP.com. If you already have S-user id or sap account, you can re-use that.</EM>&nbsp; &nbsp;<A href="https://www.sap.com/index.html" target="_blank" rel="noopener noreferrer">SAP Software Solutions | Business Applications and Technology</A></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">2.&nbsp; <EM>Create BTP trial account</EM></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Go to SAP BTP cockpit &nbsp;<A href="https://account.hanatrial.ondemand.com/trial/#/globalaccount/8b36374e-3cb7-4cef-9a58-d39f40d34f50/subaccount/960235a0-6d0f-419d-ac1d-3b0d0ce77682/service-instances&amp;//detail/4e844349-ef52-4a8e-b6c2-6ef5c8cdee43/?layout=TwoColumnsMidExpanded" target="_blank" rel="noopener nofollow noreferrer">Instances and Subscriptions - trial &lt; 5c30eb07trial &lt; Trial Home - SAP BTP Cockpit</A></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Login with your account</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_24-1750312008187.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276133iDF14BCA5E31A18CF/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_24-1750312008187.png" alt="SangeetaSingh_24-1750312008187.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Choose US East(VA)-AWS region</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_25-1750312008190.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276132i6C39E6463E6BB355/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_25-1750312008190.png" alt="SangeetaSingh_25-1750312008190.png" /></span></P><P>&nbsp;</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_26-1750312008197.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276134i5BA5DCBA98DD48D8/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_26-1750312008197.png" alt="SangeetaSingh_26-1750312008197.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Go to your Trial Account</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_27-1750312008213.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276135i8355700A11D13A82/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_27-1750312008213.png" alt="SangeetaSingh_27-1750312008213.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_28-1750312008220.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276137iDAB3636CCE6A51EA/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_28-1750312008220.png" alt="SangeetaSingh_28-1750312008220.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Go to subaccounts</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_29-1750312008226.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276136i96079688BF86405E/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_29-1750312008226.png" alt="SangeetaSingh_29-1750312008226.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><EM>3. Create new instance and setup ABAP environment in BTP account</EM></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Subaccounts &gt;&gt; Instance and Subscriptions &gt;&gt; Create</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_30-1750312008230.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276138iC68735246223AB72/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_30-1750312008230.png" alt="SangeetaSingh_30-1750312008230.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_31-1750312008240.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276140i8DB8D1E52BA2A7F5/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_31-1750312008240.png" alt="SangeetaSingh_31-1750312008240.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_32-1750312008248.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276139iBDBE6C051DC059A8/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_32-1750312008248.png" alt="SangeetaSingh_32-1750312008248.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_33-1750312008256.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276143iF407D05173CFB50C/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_33-1750312008256.png" alt="SangeetaSingh_33-1750312008256.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Setup ABAP environment</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_34-1750312008269.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276144i32FBDB468EA1D69E/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_34-1750312008269.png" alt="SangeetaSingh_34-1750312008269.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Enter your BTP account e-mail id here</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_35-1750312008274.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276142i6D3ADD9793B2FE2B/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_35-1750312008274.png" alt="SangeetaSingh_35-1750312008274.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Create service key</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_36-1750312008279.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276145i1118F8433CDB0278/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_36-1750312008279.png" alt="SangeetaSingh_36-1750312008279.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Enter your e-mail id with which you created BTP account</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_37-1750312008287.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276147i9E20125F9E69CB53/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_37-1750312008287.png" alt="SangeetaSingh_37-1750312008287.png" /></span>4.</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><EM>4. Download/Install and setup eclipse</EM></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><A href="https://tools.hana.ondemand.com/#abap" target="_blank" rel="noopener nofollow noreferrer">SAP Development Tools</A></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_38-1750312008292.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276146i66733E45865642D2/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_38-1750312008292.png" alt="SangeetaSingh_38-1750312008292.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_39-1750312008299.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276150iFBCF02676CC87EB1/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_39-1750312008299.png" alt="SangeetaSingh_39-1750312008299.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Launch eclipse from downloaded folder</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Install ADT plug in</P><OL><LI>In Eclipse, choose in the menu bar&nbsp;<STRONG>Help &gt; Install New Software...</STRONG></LI><LI>Enter the URL&nbsp;<STRONG><A href="https://tools.hana.ondemand.com/latest" target="_blank" rel="noopener nofollow noreferrer">https://tools.hana.ondemand.com/latest</A></STRONG></LI><LI>Press&nbsp;<STRONG>Enter</STRONG>&nbsp;to display the available features.</LI><LI>Select&nbsp;<STRONG>ABAP Development Tools</STRONG>&nbsp;and choose&nbsp;<STRONG>Next</STRONG>.</LI><LI>On the next wizard page, you get an overview of the features to be installed. Choose&nbsp;<STRONG>Next</STRONG>.</LI><LI>Confirm the&nbsp;<STRONG>license agreements</STRONG>&nbsp;and choose&nbsp;<STRONG>Finish</STRONG>&nbsp;to start the installation.</LI><LI><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_40-1750312008304.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276149iAE03D815274636B9/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_40-1750312008304.png" alt="SangeetaSingh_40-1750312008304.png" /></span></LI></OL><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Connect eclipse with ABAP on Cloud</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">File &gt;&gt; New &gt;&gt; ABAP Cloud Project</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_41-1750312008310.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276148i0194CDF445BA6615/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_41-1750312008310.png" alt="SangeetaSingh_41-1750312008310.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_42-1750312008315.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276154i9BBF46B4E96B0AFD/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_42-1750312008315.png" alt="SangeetaSingh_42-1750312008315.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Go to your BTP account and click on view Service key</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_43-1750312008322.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276153iEF33FCBACD4F1210/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_43-1750312008322.png" alt="SangeetaSingh_43-1750312008322.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Copy url from your service key and paste in ABAP Service Instance URL in eclipse</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_44-1750312008325.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276152iB48D206634E5B6F3/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_44-1750312008325.png" alt="SangeetaSingh_44-1750312008325.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_45-1750312008330.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276155i2237F607811F8899/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_45-1750312008330.png" alt="SangeetaSingh_45-1750312008330.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Login with your BTP account in browser</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_46-1750312008333.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276156iC2BF6A7126482C95/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_46-1750312008333.png" alt="SangeetaSingh_46-1750312008333.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Click Finish</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="SangeetaSingh_47-1750312008338.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276157i58E90BB9839C66CC/image-size/medium?v=v2&amp;px=400" role="button" title="SangeetaSingh_47-1750312008338.png" alt="SangeetaSingh_47-1750312008338.png" /></span></P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Your ABAP environment on cloud will be connected.</P><P>&nbsp;</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Thanks for visiting.&nbsp;</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Please do like, share and comment.</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">Sangeeta Singh</P><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">&nbsp;</P><P><A href="https://sangeetasinghdotblog.wordpress.com/" target="_self" rel="nofollow noopener noreferrer">Website</A></P><DIV class=""><DIV class=""><A class="" href="https://www.linkedin.com/mynetwork/discovery-see-all/?usecase=PEOPLE_FOLLOWS&amp;followMember=sangeeta-singh-4bb3aa117" target="_blank" rel="noopener nofollow noreferrer">Linkedin</A></DIV><DIV class=""><A class="" href="https://medium.com/@sangeetasinghofficial17" target="_self" rel="nofollow noopener noreferrer">Medium</A></DIV><DIV class="">&nbsp;</DIV><DIV class=""><A class="" href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" target="_blank">ABAP Development</A><SPAN>&nbsp;</SPAN><SPAN>&nbsp;</SPAN><SPAN>&nbsp;</SPAN><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+Community/pd-p/486157991894093153608181816584982" target="_blank">SAP Community </A></DIV><DIV class=""><a href="https://community.sap.com/t5/c-khhcw49343/SAP+HANA+service+for+SAP+BTP/pd-p/73555000100800001352" class="lia-product-mention" data-product="654-1">SAP HANA service for SAP BTP</a>&nbsp;<a href="https://community.sap.com/t5/c-khhcw49343/PostgreSQL+on+SAP+BTP%25252C+hyperscaler+option/pd-p/84478839-5ee3-43c6-a92e-0474fec95b3e" class="lia-product-mention" data-product="1219-1">PostgreSQL on SAP BTP, hyperscaler option</a>&nbsp; <a href="https://community.sap.com/t5/c-khhcw49343/SAP+HANA+Enterprise+Cloud/pd-p/161153735145145802176671450589155" class="lia-product-mention" data-product="329-1">SAP HANA Enterprise Cloud</a>&nbsp;</DIV><DIV class="">&nbsp;</DIV></DIV><P>&nbsp;</P> 2025-06-19T14:56:53.611000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/sap-managed-rap-based-on-header-and-item-table/ba-p/14133709 SAP Managed RAP based on Header and Item table 2025-06-22T01:34:51.835000+02:00 anjan_paul https://community.sap.com/t5/user/viewprofilepage/user-id/183963 <P>Steps:</P><P>1. Create Data Base table for PO Header.</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'PO Header' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zpo_header { key client : abap.clnt not null; key pono : ebeln not null; pocompany : bukrs; podate : abap.dats; podesc : abap.char(20); postatus : abap.char(1); }</code></pre><P>2. Create PO Item Database table.</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'PO Item' @AbapCatalog.enhancement.category : #EXTENSIBLE_ANY @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zpo_item { key client : abap.clnt not null; @AbapCatalog.foreignKey.screenCheck : false key pono : ebeln not null with foreign key [1..*,1] zpo_header where client = zpo_item.client and pono = zpo_item.pono; key poitem : ebelp not null; @Semantics.quantity.unitOfMeasure : 'zpo_item.unit' quantity : abap.quan(10,0); unit : abap.unit(3); }</code></pre><P>3. Create Base CDS Header view.</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Base view for po' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define root view entity z_po_header_base as select from zpo_header { key pono as Pono, pocompany as Pocompany, podate as Podate, podesc as Podesc, postatus as Postatus }</code></pre><P>4. Create Base CDS item view.</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Base view for po item' @Metadata.ignorePropagatedAnnotations: true define root view entity z_po_item_base as select from zpo_item { key pono as Pono, key poitem as Poitem, @Semantics.quantity.unitOfMeasure : 'Unit' quantity as Quantity, unit as Unit }</code></pre><P>5. Create Composite Header CDS view.</P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Composit view for po' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define root view entity z_po_header_composit as select from z_po_header_base composition [1..*] of z_po_item_composit as _item { key Pono, Pocompany, Podate, Podesc, Postatus, _item }</code></pre><P>6. Create Composite Item CDS view.</P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Composit view for po item' @Metadata.ignorePropagatedAnnotations: true define view entity z_po_item_composit as select from z_po_item_base association to parent z_po_header_composit as _header on $projection.Pono = _header.Pono { key Pono, key Poitem, @Semantics.quantity.unitOfMeasure : 'Unit' Quantity, Unit, _header }</code></pre><P>&nbsp;</P><P>7. Create Consumption CDS Header view.</P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Consumption view for po' @Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define root view entity z_po_header_consumption provider contract transactional_query as projection on z_po_header_composit { key Pono, Pocompany, Podate, Podesc, Postatus, /* Associations */ _item : redirected to composition child z_po_item_consumption }</code></pre><P>8. Create Consumption Item CDS view.</P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Consumption view for po item' @Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define view entity z_po_item_consumption as projection on z_po_item_composit { key Pono, key Poitem, @Semantics.quantity.unitOfMeasure : 'Unit' Quantity, Unit, /* Associations */ _header : redirected to parent z_po_header_consumption }</code></pre><P>9. Create Metadata Extension for Header.</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CUSTOMER annotate entity z_po_header_consumption with { <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.facet: [{ purpose: #STANDARD, position: 10, label: 'Header', type: #IDENTIFICATION_REFERENCE }, { purpose: #STANDARD, position: 20, label: 'Item', type: #LINEITEM_REFERENCE, targetElement: '_item' }] @UI.selectionField: [{ position: 10 }] @UI.lineItem: [{ position: 10, label: 'PO No' }] @UI.identification: [{ position: 10, label: 'Po NO' }] Pono; @UI.selectionField: [{ position: 20 }] @UI.lineItem: [{ position: 20, label: 'Company' }] @UI.identification: [{ position: 20, label: 'Company' }] Pocompany; @UI.selectionField: [{ position: 30 }] @UI.lineItem: [{ position: 30, label: 'PO Date' }] @UI.identification: [{ position: 30, label: 'PO Date' }] Podate; @UI.lineItem: [{ position: 40, label: 'Desc' }] @UI.identification: [{ position: 40, label: 'Desc' }] Podesc; @UI.lineItem: [{ position: 50, label: 'Status' }] @UI.identification: [{ position: 50, label: 'Status' }] Postatus; }</code></pre><P>10.&nbsp; Create Metadata extension for Item .</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CUSTOMER annotate entity z_po_item_consumption with { <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>.facet: [{ purpose: #STANDARD, position: 10, label: 'Item', type: #IDENTIFICATION_REFERENCE }] @UI.lineItem: [{ position: 10, label: 'Po no' }] @UI.identification: [{ position: 10, label: 'Po no' }] Pono; @UI.lineItem: [{ position: 20, label: 'Item' }] @UI.identification: [{ position: 20, label: 'Item' }] Poitem; @UI.lineItem: [{ position: 30, label: 'Quantity' }] @UI.identification: [{ position: 30, label: 'Quantity' }] Quantity; @UI.lineItem: [{ position:40, label: 'Unit' }] @UI.identification: [{ position: 40, label: 'Unit' }] Unit; }</code></pre><P>11. Create Behavior Definition of Composite view.</P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_po_header_composit unique; strict ( 2 ); define behavior for z_po_header_composit //alias &lt;alias_name&gt; persistent table zpo_header lock master authorization master ( instance ) //etag master &lt;field_name&gt; { create; update; delete; association _item { create; } } define behavior for z_po_item_composit //alias &lt;alias_name&gt; persistent table zpo_item lock dependent by _header authorization dependent by _header //etag master &lt;field_name&gt; { update; delete; field ( readonly ) Pono; association _header; }</code></pre><P>12. Create Projection Behavior Definition.</P><pre class="lia-code-sample language-abap"><code>projection; strict ( 2 ); define behavior for z_po_header_consumption //alias &lt;alias_name&gt; { use create; use update; use delete; use association _item { create; } } define behavior for z_po_item_consumption //alias &lt;alias_name&gt; { use update; use delete; use association _header; }</code></pre><P>13. Create Service Definition.</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Service Definition fo PO Header' define service Z_SV_PO_HEADER { expose z_po_header_consumption; expose z_po_item_consumption; }</code></pre><P>14. Create Service Binding.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="anjan_paul_1-1750548575837.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277298i246C5370ABCB5340/image-size/medium?v=v2&amp;px=400" role="button" title="anjan_paul_1-1750548575837.png" alt="anjan_paul_1-1750548575837.png" /></span></P><P>&nbsp;</P><P>15. Now Application can be run from Preview. Header and Item can be created .</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="anjan_paul_2-1750548645413.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277299iC1DAB4E79DC427FD/image-size/medium?v=v2&amp;px=400" role="button" title="anjan_paul_2-1750548645413.png" alt="anjan_paul_2-1750548645413.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="anjan_paul_3-1750548679744.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277300i0D7B443BDBCE4487/image-size/medium?v=v2&amp;px=400" role="button" title="anjan_paul_3-1750548679744.png" alt="anjan_paul_3-1750548679744.png" /></span></P><P>16. Records created in Header and Item table.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="anjan_paul_4-1750548764141.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277301iA72D85CBB8D96D03/image-size/medium?v=v2&amp;px=400" role="button" title="anjan_paul_4-1750548764141.png" alt="anjan_paul_4-1750548764141.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="anjan_paul_5-1750548793518.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277302iD08F7F6378AC46BC/image-size/medium?v=v2&amp;px=400" role="button" title="anjan_paul_5-1750548793518.png" alt="anjan_paul_5-1750548793518.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P><P>&nbsp;</P> 2025-06-22T01:34:51.835000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/universal-odata-mcp-bridge-or-how-i-accidentally-made-15-000-enterprise/ba-p/14134696 Universal OData ↔ MCP Bridge; Or: How I Accidentally Made 15,000 Enterprise Services Talk to AI 2025-06-23T18:50:46.751000+02:00 Alice_V https://community.sap.com/t5/user/viewprofilepage/user-id/609259 <H3 id="toc-hId-1862333795">Or: How I Accidentally Made 15,000 Enterprise Services Talk to AI</H3><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Slide2.PNG" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277833iAB229214367BE13A/image-size/large?v=v2&amp;px=999" role="button" title="Slide2.PNG" alt="Slide2.PNG" /></span></P><P class="">In March 2025 I realised the "hard part" of enterprise AI integration was already solved by metadata we've had for years. Two hundred MCP servers suddenly became <STRONG>15,000+</STRONG> – with one simple translator. <span class="lia-unicode-emoji" title=":rocket:">🚀</span></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-1665820290">What Problem Are We Solving?</H3><P class="">Hey folks! <span class="lia-unicode-emoji" title=":waving_hand:">👋</span> This is the logical continuation of my <STRONG>ABAP-native AI</STRONG> journey:</P><UL class=""><LI><P class=""><STRONG>ZVDB &amp; ZLLM</STRONG> brought AI <EM>into</EM> ABAP (vector search, LangChain-lite, local inference)</P></LI><LI><P class=""><STRONG>This bridge</STRONG> brings ABAP — and every other OData system — <EM>to</EM> AI</P></LI></UL><P class="">Enterprises sit on thousands of OData endpoints that already expose clean business semantics, yet modern AI assistants can't reach them. All that was missing was a translator.</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-1469306785">The "15,000+ MCP Servers" Moment</H3><TABLE border="1" width="100%"><TBODY><TR><TD width="50%"><STRONG>Ecosystem</STRONG></TD><TD width="50%"><STRONG>OData services made AI-ready</STRONG></TD></TR><TR><TD width="50%">SAP (ECC → S/4 &amp; BTP)</TD><TD width="50%">≈ 10,000</TD></TR><TR><TD width="50%">Microsoft Dynamics</TD><TD width="50%">≈ 1,500</TD></TR><TR><TD width="50%">Salesforce</TD><TD width="50%">≈ 800</TD></TR><TR><TD width="50%">Oracle Cloud ERP</TD><TD width="50%">≈ 2,000</TD></TR><TR><TD width="50%">SharePoint, ServiceNow &amp; friends</TD><TD width="50%">≈ 1,000</TD></TR></TBODY></TABLE><P class=""><STRONG>Total:</STRONG> <EM>15,000+</EM> enterprise-grade services now surface as first-class MCP tools.¹ Not toys—systems that move real money.</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-1272793280">TL;DR (Four Bullets, Promise!)</H3><OL class=""><LI><P class=""><STRONG>Code</STRONG> → GitHub: <STRONG>oisee/odata_mcp</STRONG> (Python) &amp; <STRONG>oisee/odata_mcp_go</STRONG> (Go) (link in first comment)</P></LI><LI><P class=""><STRONG>Problem</STRONG> → $2T of software speaks OData; 0% speaks MCP</P></LI><LI><P class=""><STRONG>Solution</STRONG> → Bridge auto-discovers every entity/action; zero config</P></LI><LI><P class=""><STRONG>Result</STRONG> → Your ERP landscape is AI-accessible in <STRONG>under two minutes</STRONG></P></LI></OL><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-1076279775">Why This Matters—The "So What?"</H3><TABLE border="1" width="100%"><TBODY><TR><TD width="50%"><STRONG>Role</STRONG></TD><TD width="50%">&nbsp;</TD></TR><TR><TD width="50%">CTO / Architect</TD><TD width="50%">All legacy &amp; cloud systems become AI-ready today—no vendor roadmap, no middleware</TD></TR><TR><TD width="50%">Developer</TD><TD width="50%">One interface for SAP, Dynamics, Oracle, Salesforce—write once, chat everywhere</TD></TR><TR><TD width="50%">Business user</TD><TD width="50%">"Claude, approve all POs &lt; $50k" – and it just happens</TD></TR></TBODY></TABLE><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-879766270">The "Wait, That's It?" Moment</H3><UL class=""><LI><P class=""><STRONG>OData</STRONG> = REST + machine-readable metadata</P></LI><LI><P class=""><STRONG>MCP</STRONG> = JSON-RPC + tool definitions AI assistants understand</P></LI><LI><P class=""><STRONG>Bridge</STRONG> = translate the metadata to tool definitions. That's it.</P></LI></UL><P class=""><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>Just translate between them—and you've unlocked the whole enterprise. <span class="lia-unicode-emoji" title=":thinking_face:">🤔</span></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-683252765">Two Flavours, Same Power</H3><TABLE border="1" width="100%"><TBODY><TR><TD width="33.333333333333336%" height="30px">&nbsp;</TD><TD width="33.333333333333336%" height="30px">Python</TD><TD width="33.333333333333336%" height="30px">Go</TD></TR><TR><TD width="33.333333333333336%" height="30px">Startup</TD><TD width="33.333333333333336%" height="30px">~3s</TD><TD width="33.333333333333336%" height="30px">~0.3s</TD></TR><TR><TD width="33.333333333333336%" height="30px">Memory</TD><TD width="33.333333333333336%" height="30px">~150 MB</TD><TD width="33.333333333333336%" height="30px">~30 MB</TD></TR><TR><TD width="33.333333333333336%" height="30px">Best for</TD><TD width="33.333333333333336%" height="30px">Prototyping &amp; demos</TD><TD width="33.333333333333336%" height="30px">Production workloads</TD></TR><TR><TD width="33.333333333333336%" height="30px">Shared superpowers</TD><TD width="33.333333333333336%" height="30px">Full CRUD, function imports, CSRF juggling (hi SAP <span class="lia-unicode-emoji" title=":waving_hand:">👋</span>), Basic auth, Cookies auth</TD></TR></TBODY></TABLE><H3 id="toc-hId-486739260">Demo: From Skepticism to "Holy Wow"</H3><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="2025-06-23_11-33-45.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277775i07541A61F843E60E/image-size/large?v=v2&amp;px=999" role="button" title="2025-06-23_11-33-45.png" alt="2025-06-23_11-33-45.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><H3 id="toc-hId-290225755">Enterprise Reality Demo</H3><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="2025-06-23_14-15-41.png" style="width: 355px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277776i2878AED6F433C4D0/image-size/large?v=v2&amp;px=999" role="button" title="2025-06-23_14-15-41.png" alt="2025-06-23_14-15-41.png" /></span></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId-93712250">The Auto-Discovery Magic <span class="lia-unicode-emoji" title=":star:">⭐</span></H3><P class="">OData's metadata does 90% of the work; the bridge just speaks fluent MCP.</P><P class=""><STRONG>Want the deep dive?</STRONG></P><P class="">Check the repo or catch me on SAP On Azure Podcast&nbsp;<span class="lia-unicode-emoji" title=":studio_microphone:">🎙</span>️</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--178032624">The Hidden Cost of Waiting</H3><TABLE border="1" width="100%"><TBODY><TR><TD width="33.333333333333336%" height="30px">&nbsp;</TD><TD width="33.333333333333336%" height="30px"><STRONG>Vendor AI (Joule / Copilot / Einstein)</STRONG></TD><TD width="33.333333333333336%" height="30px"><STRONG>Bridge Today</STRONG></TD></TR><TR><TD width="33.333333333333336%" height="30px">Availability</TD><TD width="33.333333333333336%" height="30px">Cloud-only, phased rollout</TD><TD width="33.333333333333336%" height="30px">Any OData v2/v3—even ECC 2007</TD></TR><TR><TD width="33.333333333333336%" height="30px">Coverage</TD><TD width="33.333333333333336%" height="30px">Single vendor</TD><TD width="33.333333333333336%" height="30px">Entire landscape</TD></TR><TR><TD width="33.333333333333336%" height="30px">Time-to-value</TD><TD width="33.333333333333336%" height="30px">6-18 months</TD><TD width="33.333333333333336%" height="30px">&lt; 2 minutes</TD></TR><TR><TD width="33.333333333333336%" height="30px">Data location</TD><TD width="33.333333333333336%" height="30px">Vendor cloud</TD><TD width="33.333333333333336%" height="30px">Stays on-prem / your VPC</TD></TR><TR><TD width="33.333333333333336%" height="30px">Vendor-Lock</TD><TD width="33.333333333333336%" height="30px">High</TD><TD width="33.333333333333336%" height="30px">Zero (MIT licensed)</TD></TR></TBODY></TABLE><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--374546129">Security &amp; Governance (Because Enterprise)</H3><UL class=""><LI><P class=""><STRONG>Runs inside your network</STRONG> — nothing leaves unless you proxy it</P></LI><LI><P class=""><STRONG>Honours existing roles</STRONG> — if users can't see it in GUI or Fiori - they can't see it via MCP</P></LI><LI><P class=""><STRONG>Audit trail</STRONG>-ready — every request loggable with full context</P></LI></UL><P class="">No new attack surface—just a protocol translator.</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--571059634">The Ecosystem Just Shifted</H3><P class="">When 15,000+ production services become AI-accessible overnight, MCP stops being a dev toy and becomes the enterprise standard. This isn't iteration—it's inflection.</P><H3 id="toc-hId--767573139">A Day in Your New AI-Powered Life</H3><P class="">&nbsp;</P><PRE>09:00&nbsp; "Claude, what needs my attention?" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; → 3 POs &gt; $40k awaiting approval (SAP) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; → Customer escalation (ServiceNow) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; → Budget variance on cost center 4210 (Dynamics 365) 09:05&nbsp; "Approve the POs from established vendors, escalate to Sarah, schedule variance review." &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; → Done. Next?</PRE><P class="">Five minutes. One assistant. Zero UI clicks.</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--964086644">What Could Go Wrong? (Let's Be Honest)</H3><UL class=""><LI><P class=""><STRONG>Query complexity</STRONG>: Some OData implementations choke on deeply nested $expands</P></LI><LI><P class=""><STRONG>Rate limits</STRONG>: Your backend might not love 100 requests/second from an enthusiastic AI</P></LI><LI><P class=""><STRONG>Schema changes</STRONG>: When your OData model changes, tools need regeneration</P></LI><LI><P class=""><STRONG>Governance</STRONG>: "Claude, show me all salaries" works if your auth is broken</P></LI></UL><P class="">But these are solvable with basic ops hygiene—rate limiters, caching, and proper RBAC.</P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--1160600149">Get Rolling in Two Minutes</H3><OL><LI>download pre-built binary for your platform: <A class="" href="https://github.com/oisee/odata_mcp_go/releases/tag/v1.0.0" target="_self" rel="nofollow noopener noreferrer">Release Universal OData ↔ MCP Bridge v1.0.0 (Multi-Platform Binaries) · oisee/odata_mcp_go</A></LI><LI>copy/rename to the appropriate folder (like C:/bin/ )</LI><LI>update your <STRONG>claude_desktop_config.json </STRONG>correspondingly:</LI></OL><pre class="lia-code-sample language-json"><code>{ "mcpServers": { "northwind-go": { "args": [ "--service", "https://services.odata.org/V2/Northwind/Northwind.svc/", "--tool-shrink" ], "command": "C:/bin/odata-mcp.exe" } } }</code></pre><P class="">Add as many services as you want: just repeat with different --service argument</P><P class="">Instructions on how to build from source code - in README here:&nbsp;<A href="https://github.com/oisee/odata_mcp_go" target="_blank" rel="noopener nofollow noreferrer">oisee/odata_mcp_go</A></P><P class=""><STRONG><span class="lia-unicode-emoji" title=":star:">⭐</span>Star the repo if this unlocks value for you!</STRONG></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><H3 id="toc-hId--1357113654">What's Next</H3><UL class=""><LI><P class="">Stay tuned for next week's deep dive: "10 Mind-Blowing Things You Can Build When Your ERP Speaks AI"</P></LI></UL><P class="">But honestly? Even <EM>this</EM> changes everything.</P><H3 id="toc-hId--1553627159">Try It. Break It. Make It Better.</H3><P class="">Here's what I need from <STRONG><EM>you</EM></STRONG> amazing people:</P><OL class=""><LI><P class=""><STRONG>Try it with your systems</STRONG> - SAP, Dynamics, whatever you've got</P></LI><LI><P class=""><STRONG>Break it creatively</STRONG> - I love good bug reports</P></LI><LI><P class=""><STRONG>Add your system's quirks</STRONG> - Every OData implementation is a special snowflake</P></LI><LI><P class=""><STRONG>Share what you build</STRONG> - The crazier the use case, the better</P></LI></OL><P class="">Drop a PR, open an issue, or just share what happens when you connect your enterprise to AI.</P><H2 id="toc-hId--1456737657">Want This as an Azure Service?</H2><P class="">Look, this open-source bridge proves the concept works. But I know what you're thinking - "Great Alice, but what about enterprise deployment, monitoring, compliance, support?"</P><P class="">Fair point. What if this was available as a managed Azure service? Zero setup, enterprise SLA, built-in monitoring, automatic scaling...</P><P class="">Drop a comment if you want that. <span class="lia-unicode-emoji" title=":winking_face:">😉</span></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><P class=""><STRONG>P.S.</STRONG> Yes, it handles all the authentication properly. Yes, it respects permissions. Yes, it works with your ancient SAP system from 2007. No, I don't know why this wasn't built years ago either. (Well, actually, I <EM>might</EM> know.)</P><P class=""><STRONG>P.P.S.</STRONG> First prompt I'll run in production: <STRONG>"Claude, find every place we're leaving money on the table."</STRONG> <span class="lia-unicode-emoji" title=":money_bag:">💰</span></P><DIV class=""><HR /><DIV class="">&nbsp;</DIV></DIV><P class="">¹ Counts derived from SAP annual report (2024), Microsoft Dynamics docs, Salesforce API catalog, Oracle ERP Cloud guides, and the public <EM>awesome-mcp-servers</EM> list; full methodology in /analysis/service-counts.csv.</P><P class="">#EnterpriseAI #OData #MCP #OpenSource #AIIntegrationCP #OpenSource #AIIntegration</P> 2025-06-23T18:50:46.751000+02:00 https://community.sap.com/t5/application-development-and-automation-blog-posts/implementing-bopf-actions-using-cds-based-business-objects-in-s-4hana/ba-p/14132840 Implementing BOPF Actions Using CDS-Based Business Objects in S/4HANA 2025-06-24T09:40:16.716000+02:00 Ruhoolla_Khan https://community.sap.com/t5/user/viewprofilepage/user-id/1451103 <P><STRONG><SPAN>Introduction</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>In SAP S/4HANA, Core Data Services (CDS) are widely used to define meaningful and reusable data models. When these CDS views are annotated correctly, they can automatically create a Business Object Processing Framework (BOPF) model. This helps in building business objects faster and with less manual effort.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>In real-world applications, we often need to perform actions that go beyond just creating, reading, updating, or deleting data. For example, we might need to "Active Status" the status of a record, "Cancel" a request. These kinds of operations are called actions in BOPF.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>This object explains how to add such custom actions to a CDS-based BOPF model. It helps developers extend standard functionality by including business-specific logic that users can trigger when needed.</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Steps for implementing Action for the CDS-Based Business Objects.</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Enhancing CDS-Based BOPF Objects with Custom Actions in S/4HANA.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Defining and Implementing Actions in BOPF via CDS Views.</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.sqlViewName: 'ZCFMEAL_SQL' @AbapCatalog.compiler.compareFilter: true @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Flight Meal Application, Consumption View' @OData.publish: true @Metadata.allowExtensions: true @ObjectModel:{ modelCategory: #BUSINESS_OBJECT, compositionRoot: true, transactionalProcessingEnabled: true, createEnabled: true, updateEnabled: true, deleteEnabled: true, writeActivePersistence: 'ZAP_FLIGHT_MEAL' } define view ZCFMEAL as select from zap_flight_meal association [1] to scarr as _Airline on $projection.carrid = _Airline.carrid association [1] to sflight as _FlightInfo on $projection.carrid = _FlightInfo.carrid and $projection.connid = _FlightInfo.connid association [1] to smeal as _Meals on $projection.carrid = _Meals.carrid and $projection.meal = _Meals.mealnumber { @UI.facet: [{ purpose: #STANDARD, label: 'Meals', type: #IDENTIFICATION_REFERENCE, position: 10 }] @UI.lineItem: [{ position: 10, label: 'Meal ID' }, { position: 10, type: #FOR_ACTION, dataAction: 'BOPF:SET_STATUS', label: 'Active Status' } ] @UI.identification: [{ position: 10, label: 'Meal ID' }] key meal_id, @UI.lineItem: [{ position: 20, label: 'Carrier' }] @UI.identification: [{ position: 20, label: 'Carrier' }] @ObjectModel.foreignKey.association: '_Airline' carrid, @UI.lineItem: [{ position: 30, label: 'Connection' }] @UI.identification: [{ position: 30, label: 'Connection' }] @ObjectModel.foreignKey.association: '_FlightInfo' connid, @UI.lineItem: [{ position: 40, label: 'Meal' }] @UI.identification: [{ position: 40, label: 'Meal' }] @ObjectModel.foreignKey.association: '_Meals' meal, @UI.lineItem: [{ position: 50, label: 'Total seats' }] @UI.identification: [{ position: 50, label: 'Total seats' }] total_seats, @UI.lineItem: [{ position: 10, label: 'Status' }] @UI.identification: [{ position: 10, label: 'Status' }] status, _Airline, _FlightInfo, _Meals } </code></pre><P><SPAN class=""><SPAN class="">Once the CDS view is activated, the corresponding BOPF object is automatically generated. You can view it using transaction code BOBX and </SPAN><SPAN class="">proceed</SPAN><SPAN class=""> to define the action.</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_0-1750417416815.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277067i27A30AF97850D8B2/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_0-1750417416815.png" alt="Ruhoolla_Khan_0-1750417416815.png" /></span></P><P><SPAN>Next, implement the business logic for the action in the corresponding BOPF action class.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_1-1750417483251.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277073iCB5D6C61A220C0E3/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_1-1750417483251.png" alt="Ruhoolla_Khan_1-1750417483251.png" /></span></P><P><SPAN>The action implementation class inherits predefined methods from the BOPF framework, such as EXECUTE_ACTION.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_2-1750417483252.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277074i2980B0ABB310C0D0/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_2-1750417483252.png" alt="Ruhoolla_Khan_2-1750417483252.png" /></span><SPAN>&nbsp;</SPAN></P><P><SPAN>Implementation:</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_0-1750419067172.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277113iD1D97EA89D842DEB/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_0-1750419067172.png" alt="Ruhoolla_Khan_0-1750419067172.png" /></span></P><P><SPAN>Activate and generate the BOPF object.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Now add the service and utilize it in the front-end.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_4-1750417483254.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277077i426517115DDC3F48/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_4-1750417483254.png" alt="Ruhoolla_Khan_4-1750417483254.png" /></span></P><P><SPAN>Add the service by Selecting and provide the package name.&nbsp;&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_5-1750417483255.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277078iBC9CCB55F5663122/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_5-1750417483255.png" alt="Ruhoolla_Khan_5-1750417483255.png" /></span></P><P>You'll get an information that the metadata has been loaded for that service.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_6-1750417483256.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277076iCAC7BF6466C2C60B/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_6-1750417483256.png" alt="Ruhoolla_Khan_6-1750417483256.png" /></span></P><P><SPAN>Test the service.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_7-1750417483257.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277080i76170F7BD361CE8F/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_7-1750417483257.png" alt="Ruhoolla_Khan_7-1750417483257.png" /></span></P><P><SPAN>Now by using the Odata service create the basic Fiori application</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Steps to create basic Fiori application:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Use any tool for creating Fiori like VS Code or SAP Business Application Studio (BAS).</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Open Application generator-&gt; select the template -&gt; provide the service -&gt;select the entity-&gt; finish and run the application</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_8-1750417483257.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277081i50E984F46D52C41F/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_8-1750417483257.png" alt="Ruhoolla_Khan_8-1750417483257.png" /></span><SPAN>&nbsp;</SPAN><SPAN>Once the application has been generated, you can see that an action button will appear in the Fiori front-end application.&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Result:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_9-1750417483258.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277079iE48718AB41E3C5DC/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_9-1750417483258.png" alt="Ruhoolla_Khan_9-1750417483258.png" /></span></P><P><SPAN>As all the status are in ‘NO’ once we select the record and click on that action the records get updated as shown below.</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Ruhoolla_Khan_10-1750417483259.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277082i99B5BAF53AD2E07B/image-size/large?v=v2&amp;px=999" role="button" title="Ruhoolla_Khan_10-1750417483259.png" alt="Ruhoolla_Khan_10-1750417483259.png" /></span></P><P><STRONG><SPAN>Conclusion:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Implementing BOPF actions via CDS views in S/4HANA demonstrates the power of combining declarative modeling with robust transactional logic. By leveraging CDS annotations and standard frameworks, developers can deliver efficient, user-friendly, and scalable business applications—reducing custom code while staying aligned with SAP’s clean core principles.</SPAN><SPAN>&nbsp;</SPAN></P> 2025-06-24T09:40:16.716000+02:00 https://community.sap.com/t5/application-development-and-automation-blog-posts/tree-view-in-rap/ba-p/14135071 Tree view in RAP 2025-06-24T09:43:15.825000+02:00 Vivek_Sahu_21 https://community.sap.com/t5/user/viewprofilepage/user-id/1451075 <P><SPAN>In this blog we will cover:</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Introduction,</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Architecture overview,</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Scenario,</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Procedure,</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Conclusion.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><U><STRONG><FONT size="6">Introduction:&nbsp;</FONT></STRONG></U></P><P><SPAN>The </SPAN><STRONG><SPAN>CDS hierarchy</SPAN></STRONG><SPAN> in SAP ABAP is used to define </SPAN><STRONG><SPAN>recursive, tree-like relationships</SPAN></STRONG><SPAN> in data directly within Core Data Services (CDS) views. It allows structured, hierarchical data (like manager-employee, material categories, sales orgs, BOMs, etc.) to be represented and consumed easily in UI applications and analytics tools.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>In the </SPAN><STRONG><SPAN>RAP (RESTful ABAP Programming Model)</SPAN></STRONG><SPAN>, a </SPAN><STRONG><SPAN>Tree View</SPAN></STRONG><SPAN> is used to </SPAN><STRONG><SPAN>visualize hierarchical (recursive) data structures</SPAN></STRONG><SPAN> in the UI—typically in </SPAN><STRONG><SPAN>Fiori Elements</SPAN></STRONG><SPAN> apps such as List Reports with tree tables.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Tree View allows end users to </SPAN><STRONG><SPAN>navigate data in a parent-child format</SPAN></STRONG><SPAN> (e.g., managers → employees, sales org → region → country).</SPAN></P><P><SPAN>├── Region North America</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>│&nbsp;&nbsp; ├── Country USA</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>│&nbsp;&nbsp; └── Country Canada</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>└── Region Europe</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp; ├── Country Germany</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp; └── Country France</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>To enable a Tree View in a RAP app:</SPAN><SPAN>&nbsp;</SPAN></P><OL><LI><STRONG><SPAN>Model recursive data in a CDS view</SPAN></STRONG><SPAN> (e.g., employee-manager, sales org tree)</SPAN><SPAN>&nbsp;</SPAN></LI><LI><SPAN>Create a </SPAN><STRONG><SPAN>CDS hierarchy</SPAN></STRONG><SPAN> (</SPAN><SPAN>define hierarchy</SPAN><SPAN>)</SPAN><SPAN>&nbsp;</SPAN></LI><LI><SPAN>Use a </SPAN><STRONG><SPAN>C_ projection view</SPAN></STRONG><SPAN> to expose the hierarchy using:</SPAN><SPAN>&nbsp;&nbsp;</SPAN><a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1599241">@odata</a>.hierarchy.recursiveHierarchy: [ { entity.name: 'ZVS_I_SALES_ORG_HN' } ]<SPAN>&nbsp;</SPAN></LI><LI><SPAN>Add your entity to </SPAN><STRONG><SPAN>Service Definition</SPAN></STRONG><SPAN> and </SPAN><STRONG><SPAN>Service Binding</SPAN></STRONG><SPAN>&nbsp;</SPAN></LI><LI><SPAN>Run the Fiori app (it will automatically detect and display a tree)</SPAN><SPAN>&nbsp;</SPAN></LI></OL><P><U><STRONG><FONT size="6">Treeviews: Architecture Overview&nbsp;</FONT></STRONG></U></P><P><SPAN>The implementation of a treeview in the ABAP RESTful Application Programming Model (RAP) requires different entities depending on whether the treeview should be read-only or editable.</SPAN><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Architecture Overview: Read-Only Treeview</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750743710426.jpeg" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277974i2891481FDCFB3EFE/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750743710426.jpeg" alt="Vivek_Sahu_21_0-1750743710426.jpeg" /></span></P><P>&nbsp;</P><P><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Architecture Overview: Read-Only Tree View in CDS</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>To enable a read-only hierarchical display of data in the UI, the following CDS artifacts are used in combination:</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><STRONG><SPAN>Database Table</SPAN></STRONG><SPAN>&nbsp;<BR /></SPAN><SPAN>A custom database table holds the hierarchical data structure.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><STRONG><SPAN>Interface View</SPAN></STRONG><SPAN>&nbsp;<BR /></SPAN><SPAN>This CDS view entity is built on top of the database table and defines the data model. It includes a self-association to represent the parent-child hierarchy within the same dataset.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><STRONG><SPAN>CDS Hierarchy</SPAN></STRONG><SPAN>&nbsp;<BR /></SPAN><SPAN>A </SPAN><I><SPAN>persistent CDS hierarchy</SPAN></I><SPAN> is created using the </SPAN><SPAN>DEFINE HIERARCHY</SPAN><SPAN> statement. It provides a hierarchical interpretation of the interface view, enabling the framework to understand how records are nested.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><STRONG><SPAN>Projection View</SPAN></STRONG><SPAN>&nbsp;<BR /></SPAN><SPAN>This view projects the interface view and incorporates the CDS hierarchy to expose the structured, hierarchical data as required by the UI.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><STRONG><SPAN>Service Definition and Service Binding</SPAN></STRONG><SPAN>&nbsp;<BR /></SPAN><SPAN>These are created to expose the CDS projection view as an OData service. This step enables the consumption of hierarchical data in SAP Fiori or other UI frameworks.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><STRONG><SPAN>Architecture Overview: Editable Treeview with Draft</SPAN></STRONG></P><P><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750744114176.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/277982i08F2A2C1F5D8F5DC/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750744114176.png" alt="Vivek_Sahu_21_0-1750744114176.png" /></span></P><P>&nbsp;</P><P><STRONG><SPAN>Editable Tree View with Draft Enablement – Architecture Overview</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>To enable an </SPAN><STRONG><SPAN>editable tree view with draft functionality</SPAN></STRONG><SPAN>, the following key artifacts work together to define and expose the hierarchical data structure to the UI:</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><STRONG>Database table:</STRONG></P><UL><LI><SPAN><SPAN class=""><SPAN class="">Active and draft tables</SPAN></SPAN><SPAN class=""><SPAN class=""> store the hierarchical data and hierarchy directory separately, supporting draft-enabled transactional scenarios.</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></SPAN></LI></UL><P><STRONG><SPAN class="">CDS view Entities (Interface Views):</SPAN></STRONG></P><UL><LI><SPAN>Interface views reference the underlying database tables and act as the </SPAN><STRONG><SPAN>first projection layer</SPAN></STRONG><SPAN>.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>The CDS view for the hierarchical data must include:</SPAN><SPAN>&nbsp;</SPAN><UL><LI><SPAN>A </SPAN><STRONG><SPAN>self-association</SPAN></STRONG><SPAN> to represent the parent-child relationship within the same entity (enabling hierarchy logic).</SPAN><SPAN>&nbsp;</SPAN></LI><LI><SPAN>A </SPAN><STRONG><SPAN>one-to-many association</SPAN></STRONG><SPAN> to link with the hierarchy directory entity.</SPAN><SPAN>&nbsp;</SPAN></LI></UL></LI></UL><P><STRONG>CDS Hierarchy:</STRONG></P><UL><LI><SPAN>A </SPAN><STRONG><SPAN>persistent CDS hierarchy</SPAN></STRONG><SPAN> is defined using </SPAN><SPAN>DEFINE HIERARCHY</SPAN><SPAN>.</SPAN></LI><LI><SPAN>It enables hierarchical interpretation for the data exposed by the first-layer CDS view.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><STRONG>Base CDS views:</STRONG></P><UL><LI><SPAN>These views enrich the model with </SPAN><STRONG><SPAN>compositional information</SPAN></STRONG><SPAN>.</SPAN><SPAN>&nbsp;</SPAN><UL><LI><SPAN>The </SPAN><STRONG><SPAN>hierarchy directory view</SPAN></STRONG><SPAN> acts as the </SPAN><STRONG><SPAN>composition root</SPAN></STRONG><SPAN> (parent).</SPAN><SPAN>&nbsp;</SPAN></LI><LI><SPAN>The </SPAN><STRONG><SPAN>hierarchical data view</SPAN></STRONG><SPAN> acts as the </SPAN><STRONG><SPAN>composition child</SPAN></STRONG><SPAN>.</SPAN><SPAN>&nbsp;</SPAN></LI></UL></LI></UL><P><STRONG>Behaviour Definition for base views:</STRONG></P><UL><LI><SPAN>Defines </SPAN><STRONG><SPAN>transactional behavior</SPAN></STRONG><SPAN>, including:</SPAN><SPAN>&nbsp;</SPAN><UL><LI><STRONG><SPAN>Draft capability</SPAN></STRONG><SPAN>&nbsp;</SPAN></LI><LI><SPAN>Editing operations required by the UI.</SPAN><SPAN>&nbsp;</SPAN></LI></UL></LI></UL><P><STRONG>Projection views:</STRONG></P><UL><LI><SPAN>Serve the </SPAN><STRONG><SPAN>consumption layer</SPAN></STRONG><SPAN>:</SPAN><SPAN>&nbsp;</SPAN><UL><LI><SPAN>For the hierarchy directory: A projection view supports transactional queries.</SPAN><SPAN>&nbsp;</SPAN></LI><LI><SPAN>For hierarchical data: A projection view combines interface view data with hierarchical logic using the </SPAN><SPAN>@OData.hierarchy.recursiveHierarchy</SPAN><SPAN> annotation (referring to the CDS hierarchy).</SPAN><SPAN>&nbsp;</SPAN></LI></UL></LI></UL><P><STRONG>Projection behaviour definition:</STRONG></P><UL><LI><SPAN>Describes the behavior of projection views, allowing:</SPAN><SPAN>&nbsp;</SPAN><UL><LI><STRONG><SPAN>Custom logic</SPAN></STRONG><SPAN> like determinations, validations, authorizations, numbering, etc.</SPAN><SPAN>&nbsp;</SPAN></LI></UL></LI></UL><P><STRONG>Service Definition and Service Binding:</STRONG></P><UL><LI><SPAN><SPAN class=""><SPAN class="">Finally, a </SPAN></SPAN><SPAN class=""><SPAN class="">service definition</SPAN></SPAN><SPAN class=""><SPAN class=""> and </SPAN></SPAN><SPAN class=""><SPAN class="">binding</SPAN></SPAN><SPAN class=""><SPAN class=""> are created to expose the hierarchy and its data structure to the UI layer via OData.</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></SPAN></LI></UL><P><SPAN><SPAN class="">===========================================================================</SPAN></SPAN></P><P><U><STRONG><FONT size="6">Scenario for Tree view in RAP:&nbsp;</FONT></STRONG></U></P><P><SPAN>In large global companies, the </SPAN><STRONG><SPAN>Sales &amp; Distribution (SD) module</SPAN></STRONG><SPAN> often reflects the company's organizational structure. Typically, </SPAN><STRONG><SPAN>Sales Organizations</SPAN></STRONG><SPAN> are arranged in a multi-level hierarchy like this:</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750746293329.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278000iA1D1A26B7D0A30E3/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750746293329.png" alt="Vivek_Sahu_21_0-1750746293329.png" /></span></P><P><SPAN>This kind of structure helps companies manage </SPAN><STRONG><SPAN>sales performance, reporting, and operations</SPAN></STRONG><SPAN> more effectively.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>However, many systems don’t provide a </SPAN><STRONG><SPAN>read-only, easy-to-use view</SPAN></STRONG><SPAN> of this hierarchy — especially in a </SPAN><STRONG><SPAN>tree or drill-down format</SPAN></STRONG><SPAN> that users can easily navigate.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>In this blog, we’ll walk through how to model and expose this Sales Org hierarchy using </SPAN><STRONG><SPAN>CDS Hierarchies</SPAN></STRONG><SPAN>, and finally expose it through an </SPAN><STRONG><SPAN>OData service</SPAN></STRONG><SPAN> to be consumed in a Fiori UI.</SPAN><SPAN>&nbsp;</SPAN></P><P><U><STRONG><FONT size="6">Procedure:&nbsp;</FONT></STRONG></U></P><P><STRONG><SPAN>Step 1: Define the Base Table - </SPAN></STRONG><STRONG><SPAN>ZVS_DT_SALES</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>This transparent table stores the core sales organization data including parent-child relationships.</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Hierarchy: Read Only: Sales Organization' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zvs_dt_sales { key client : abap.clnt not null; key sales_org_id : abap.char(6) not null; name : abap.char(50); region : abap.char(20); country : abap.char(3); @Semantics.amount.currencyCode : 'zvs_dt_sales.currency' revenue : abap.curr(21,2); currency : /dmo/currency_code; parent_sales_org : abap.char(6); }</code></pre><P><STRONG><SPAN>Note:</SPAN></STRONG> <SPAN>parent_sales_org</SPAN><SPAN> is a self-referencing field to represent the hierarchy.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>This table contain some records:</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750746688733.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278008i35DB9521A7BF5906/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750746688733.png" alt="Vivek_Sahu_21_0-1750746688733.png" /></span></P><P>&nbsp;</P><P><STRONG><SPAN>Step 2: Interface View - </SPAN></STRONG><STRONG><SPAN>ZVS_I_SALES</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>This CDS view represents the Sales Org data and defines a </SPAN><STRONG><SPAN>self-association</SPAN></STRONG><SPAN> to establish the parent-child link.</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Interface View: Sales Organization' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define view entity zvs_i_sales as select from zvs_dt_sales association to zvs_i_sales as _Parent on $projection.ParentSalesOrg = _Parent.SalesOrgId { key sales_org_id as SalesOrgId, name as Name, region as Region, country as Country, @Semantics.amount.currencyCode: 'Currency' revenue as Revenue, currency as Currency, parent_sales_org as ParentSalesOrg, _Parent }</code></pre><P><STRONG><SPAN>Step 3: Define Hierarchy - </SPAN></STRONG><STRONG><SPAN>ZVS_I_SALES_HN</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>Using CDS hierarchy syntax, we now define a </SPAN><STRONG><SPAN>parent-child recursive hierarchy</SPAN></STRONG><SPAN>.</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label:'Sales Organization Hierarchy' define hierarchy zvs_i_sales_hn as parent child hierarchy ( source zvs_i_sales child to parent association _Parent start where ParentSalesOrg is initial siblings order by SalesOrgId ascending ) { key SalesOrgId, ParentSalesOrg }</code></pre><P><SPAN>This is where the magic happens. This hierarchy enables a recursive structure that can be rendered in Fiori Tree controls.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;</SPAN></P><P><STRONG><SPAN>Step 4: Projection View - </SPAN></STRONG><STRONG><SPAN>ZVS_C_SALES</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><SPAN>This is the final consumption layer that will be exposed as OData. The hierarchy is referenced using the </SPAN><SPAN>@OData.hierarchy.recursiveHierarchy</SPAN><SPAN> annotation.</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Projection View: Sales Organization' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality:#X, sizeCategory:#S, dataClass:#MIXED } @Metadata.allowExtensions:true @Search.searchable:true @OData.hierarchy.recursiveHierarchy: [{ entity.name: 'zvs_i_sales_hn' }] define view entity zvs_c_sales as select from zvs_i_sales association of many to one zvs_c_sales as _Parent on $projection.ParentSalesOrg = _Parent.SalesOrgId { key SalesOrgId, @Search.defaultSearchElement: true Name, Region, Country, @Semantics.amount.currencyCode: 'Currency' Revenue, Currency, ParentSalesOrg, /* Associations */ _Parent }</code></pre><P><STRONG><SPAN>Screenshot:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_1-1750747123946.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278015iBDF0BBC47997F34B/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_1-1750747123946.png" alt="Vivek_Sahu_21_1-1750747123946.png" /></span></P><P><STRONG><SPAN>Metadata extension:</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE annotate entity zvs_c_sales with { @UI: {lineItem: [{ label: 'Sales org ID', position: 10 }], identification: [{ label: 'Sales org ID', position: 10 }] } SalesOrgId; @UI: {lineItem: [{ label: 'Sales org Name', position: 20 }], identification: [{ label: 'Sales org Name', position: 20 }] } Name; @UI: {lineItem: [{ label: 'Region', position: 30 }], identification: [{ label: 'Region', position: 30 }] } Region; @UI: {lineItem: [{ label: 'Country', position: 40 }], identification: [{ label: 'Country', position: 40 }] } Country; @UI: {lineItem: [{ label: 'Revenue', position: 50 }], identification: [{ label: 'Revenue', position: 50 }] } Revenue; @UI: {lineItem: [{ label: 'Currency', position: 60 }], identification: [{ label: 'Currency', position: 60 }] } Currency; @UI: {lineItem: [{ label: 'Parent Sales org ID', position: 70 }], identification: [{ label: 'Parent Sales org ID', position: 70 }] } ParentSalesOrg; }</code></pre><P><STRONG><SPAN>Step 6: Service Binding - </SPAN></STRONG><STRONG><SPAN>ZVS_C_SALES_ORG_V4</SPAN></STRONG><SPAN>&nbsp;</SPAN></P><P>If you will choose service binding type as V2, So you will get one error:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750747822530.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278026iA1D4CE4AD614B646/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750747822530.png" alt="Vivek_Sahu_21_0-1750747822530.png" /></span></P><P>So select your Binding type as V4,</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1750747270474.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278016iE5D2B66D56C3A4F5/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_0-1750747270474.png" alt="Vivek_Sahu_21_0-1750747270474.png" /></span></P><P><STRONG>Now preview your application:&nbsp;</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_1-1750747270475.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278018i775632EE7FE87274/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_1-1750747270475.png" alt="Vivek_Sahu_21_1-1750747270475.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_2-1750747270476.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278017i237BDF6C97864655/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_2-1750747270476.png" alt="Vivek_Sahu_21_2-1750747270476.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_3-1750747270477.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/278019i79A479F9D5D0F6D5/image-size/large?v=v2&amp;px=999" role="button" title="Vivek_Sahu_21_3-1750747270477.png" alt="Vivek_Sahu_21_3-1750747270477.png" /></span></P><P><STRONG><U><FONT size="6">Conclusion:&nbsp;</FONT></U></STRONG></P><P><SPAN>Using CDS views and hierarchies in SAP S/4HANA is a simple and effective way to show the Sales Organization structure in a clear, tree-like format. It helps sales managers easily understand how different sales units are connected and how each one is performing. This setup is read-only, so the data stays safe, and it works well with Fiori apps for a smooth user experience.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Overall, this approach makes reporting and analysis easier without needing a lot of custom coding.</SPAN><SPAN>&nbsp;</SPAN></P> 2025-06-24T09:43:15.825000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/reusable-sap-cpi-interface-for-proxies-using-groovy-simple-proxy-xml-to/ba-p/14130287 Reusable SAP CPI Interface for Proxies Using Groovy: Simple Proxy XML to JSON Integration 2025-06-24T10:06:56.005000+02:00 RameshVaranganti https://community.sap.com/t5/user/viewprofilepage/user-id/51927 <H2 id="toc-hId-1733128038">Introduction</H2><P>This blog will show you how to create a single interface in SAP CPI that can be reused for processing proxy XML data from SAP S4/SAP systems or any other systems also.</P><H2 id="toc-hId-1536614533">Use Case</H2><P>We will come across situations where we need to send different sets of data with different XML structures from SAP or SAP S4 to a target application using SAP CPI.</P><P>Normally, we design a specific proxy structure for XML that the ABAP team can use to send data to the middleware. But when there are multiple XML structures and the data needs to be sent separately from the source system, we often need to create multiple proxy structures. Also, if a field name needs to be changed or a new field needs to be added, the interface must be updated each time.</P><P>I came across this situation where SAP needed to send different XML messages, and the ABAP team asked for multiple proxy structures and changes. Each different message was going to the same target application but with a different resource path. This is going to take lot of time and different interfaces are needed as each message use different path in the HTTP.</P><P>To avoid this, I used a standardized XML format with simple &lt;FieldName&gt; and &lt;FieldValue&gt; pairs, and I added a resource path identifier in the header. This way, I was able to create just one reusable interface in SAP CPI that could handle all the different incoming messages, which I then sent to the target application.</P><H2 id="toc-hId-1340101028">Architecture</H2><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ProcessFlowDiagram.svg" style="width: 601px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/275532i4F92294BF1DAE635/image-size/large?v=v2&amp;px=999" role="button" title="ProcessFlowDiagram.svg" alt="ProcessFlowDiagram.svg" /></span></P><P><STRONG>Development Steps</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="RameshVaranganti_0-1750348469253.png" style="width: 815px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276395i5EC7CF8CDA9A843E/image-dimensions/815x159?v=v2" width="815" height="159" role="button" title="RameshVaranganti_0-1750348469253.png" alt="RameshVaranganti_0-1750348469253.png" /></span></P><P>&nbsp;</P><OL><LI>Standardize Input XML in SAP</LI></OL><P>I have created Standardize SAP proxy structures into a common, uniform format with header</P><P>&lt;FieldName&gt; and &lt;FieldValue&gt; XML pair structure</P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RameshVaranganti_1-1750348505072.png" style="width: 733px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276396iE9DCF11B6B273AF4/image-dimensions/733x165?v=v2" width="733" height="165" role="button" title="RameshVaranganti_1-1750348505072.png" alt="RameshVaranganti_1-1750348505072.png" /></span></P><P>This contains Header section I will be using to identify my resource path</P><P>In SAP CPI , I have used content modifier to capture the proxy header table data and saved it in property to use in HTTP receiver adapter. This property dynamically call the endpoint.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="RameshVaranganti_2-1750348562227.png" style="width: 767px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276397i3D4C6919A939BC91/image-dimensions/767x219?v=v2" width="767" height="219" role="button" title="RameshVaranganti_2-1750348562227.png" alt="RameshVaranganti_2-1750348562227.png" /></span></P><P>&nbsp;</P><OL><LI>Groovy Script in CPI for XML to Json</LI></OL><P class="lia-indent-padding-left-30px" style="padding-left : 30px;">This Groovy script parses the incoming XML, extracts field-value pairs, and builds a JSON structure:</P><pre class="lia-code-sample language-javascript"><code>import com.sap.gateway.ip.core.customdev.util.Message; import java.util.HashMap; import groovy.xml.* import groovy.json.* def Message processData(Message message) { def xml = message.getBody(java.lang.String) def records = new XmlSlurper().parseText(xml) def jsonList = records.Record.collect { record -&gt; def map = [:] record.Item.each { item -&gt; map[item.FieldName.text()] = item.FieldValue.text() } return map } def json = JsonOutput.prettyPrint(JsonOutput.toJson(jsonList)) message.setBody(json) return message; }</code></pre><P>&nbsp;</P><OL><LI>&nbsp;Post Transformed JSON Data to Target Endpoint<P>HTTP Adapter configuration: In previous Content Modifier I have used Tablename to dynamically identify target URL.</P><P>&nbsp;</P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="RameshVaranganti_3-1750348605531.png" style="width: 611px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/276398iAB5584FE86D11973/image-dimensions/611x58?v=v2" width="611" height="58" role="button" title="RameshVaranganti_3-1750348605531.png" alt="RameshVaranganti_3-1750348605531.png" /></span><P>&nbsp;</P><P>&nbsp;</P></LI></OL><H2 id="toc-hId-1143587523">Testing</H2><P>Input XML1</P><pre class="lia-code-sample language-markup"><code>&lt;Header&gt; &lt;TableName&gt;KLAH&lt;/TableName&gt; &lt;Plant&gt;001&lt;/Plant&gt; &lt;/Header&gt; &lt;Record&gt; &lt;Item&gt; &lt;FieldName&gt;MANDT&lt;/FieldName&gt; &lt;FieldValue&gt;300&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;CLINT&lt;/FieldName&gt; &lt;FieldValue&gt;1234&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;KLART&lt;/FieldName&gt; &lt;FieldValue&gt;003&lt;/FieldValue&gt; &lt;/Item&gt; &lt;/Record&gt;</code></pre><P>Output Json1:</P><pre class="lia-code-sample language-json"><code>[ { "MANDT": "300", "CLINT": "1234", "KLART": "003" } ]</code></pre><P>example2:</P><P>Input XML</P><pre class="lia-code-sample language-markup"><code>&lt;message&gt; &lt;Record&gt; &lt;Item&gt; &lt;FieldName&gt;MANDT&lt;/FieldName&gt; &lt;FieldValue&gt;300&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;TPLNR&lt;/FieldName&gt; &lt;FieldValue&gt;001A&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;SPRAS&lt;/FieldName&gt; &lt;FieldValue&gt;E&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;PLTXT&lt;/FieldName&gt; &lt;FieldValue&gt;CheckPLTXTValueRecord1&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;PLTXU&lt;/FieldName&gt; &lt;FieldValue&gt;CheckPLTXUTValueRec1&lt;/FieldValue&gt; &lt;/Item&gt; &lt;/Record&gt; &lt;Record&gt; &lt;Item&gt; &lt;FieldName&gt;MANDT&lt;/FieldName&gt; &lt;FieldValue&gt;300&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;TPLNR&lt;/FieldName&gt; &lt;FieldValue&gt;001B&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;SPRAS&lt;/FieldName&gt; &lt;FieldValue&gt;E&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;PLTXT&lt;/FieldName&gt; &lt;FieldValue&gt;CheckPLTXTValueRecord2&lt;/FieldValue&gt; &lt;/Item&gt; &lt;Item&gt; &lt;FieldName&gt;PLTXU&lt;/FieldName&gt; &lt;FieldValue&gt;CheckPLTXUTValueRec2&lt;/FieldValue&gt; &lt;/Item&gt; &lt;/Record&gt; &lt;/message&gt;</code></pre><P>OutputJson:</P><pre class="lia-code-sample language-json"><code>[ { "MANDT": "300", "TPLNR": "001A", "SPRAS": "E", "PLTXT": "CheckPLTXTValueRecord1", "PLTXU": "CheckPLTXUTValueRec1" }, { "MANDT": "300", "TPLNR": "001B", "SPRAS": "E", "PLTXT": "CheckPLTXTValueRecord2", "PLTXU": "CheckPLTXUTValueRec2" } ]</code></pre><P>&nbsp;</P><H2 id="toc-hId-947074018">Take Away</H2><OL><LI>This design&nbsp;reusable, scalable integration strategy in SAP CPI using Groovy scripting and a generalized XML structure for simple transmissions.</LI><LI><SPAN>Implementing a single interface capable of handling multiple tables data with dynamic fields, this solution simplifies integration architecture, accelerates delivery, and reduces ongoing maintenance.</SPAN></LI><LI><SPAN>Finally it eliminates the need of create multiple interfaces for similar data transmissions if we could able to handle simple design approcahes in SAP CPI.</SPAN></LI></OL> 2025-06-24T10:06:56.005000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/custom-program-to-generate-where-used-list-for-cds-ddls-object/ba-p/14137421 Custom program to generate- Where used list for CDS DDLS Object. 2025-06-26T10:31:12.615000+02:00 Prasenjitsbist https://community.sap.com/t5/user/viewprofilepage/user-id/11946 <P>This code is not my original creation, there was already a utility code on SCN to generate the where used list of CDS DDLS object. But that code only works for 1 CDS at a time. I supplied the same code to my team and they said it would be better if it could handle multiple entries. So, I just made those few changes rest is as it is from the original and full credit goes to that developer for his/her work. This code can surely be improved using better queries and reducing loops etc. but that will be up to the developer who uses this code in future.</P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>report zpsb_util_cds_where_used. types:begin of ty_ddls_w, ddls type ddlname, o_type type trobjtype, obj_name type progname, end of ty_ddls_w, begin of ty_funcm, funcname type rs38l_fnam, pname type pname, end of ty_funcm, ty_ddls_t type standard table of ty_ddls_w with empty key, ty_funcm_t type standard table of ty_funcm with empty key. data:w_ddls_f type string, t_ddls_w type ty_ddls_t, t_ddls_final type ty_ddls_t, s_ddlname type ty_ddls_w, t_func type ty_funcm_t. selection-screen: begin of block b1 with frame title text-001. selection-screen skip 1. selection-screen begin of line. *parameters:p_rad1 radiobutton group rb1. selection-screen comment 5(20) comment1. "PARAMETERS: p_ddls1 TYPE ddlname. select-options: s_ddls1 for s_ddlname-ddls NO INTERVALS. selection-screen end of line. selection-screen skip 1. *selection-screen begin of line. *parameters:p_rad2 radiobutton group rb1. *selection-screen comment 5(20) comment2. *parameters: p_ddls2 type ddlname. *selection-screen end of line. selection-screen:end of block b1. at selection-screen output. comment1 = 'CDS Where Used:'. * comment2 = 'CDS Components:'. class lcl_event_handler definition. public section. types:begin of lty_source_code, src_cd type char1000_idoc, end of lty_source_code. data: lo_alv type ref to cl_salv_table, lt_alv type ty_ddls_t. methods constructor importing i_alv type ref to cl_salv_table. methods on_double_click for event if_salv_events_actions_table~double_click of cl_salv_events_table importing row column. endclass. class lcl_event_handler implementation. method constructor. lo_alv = i_alv. endmethod. method on_double_click. data: lt_source_cd type standard table of lty_source_code, l_obj_name type progname, l_type type trobjtype, l_ddls type ddlname. check column = 'OBJ_NAME'. l_obj_name = lt_alv[ row ]-obj_name. l_type = lt_alv[ row ]-o_type. l_ddls = lt_alv[ row ]-ddls. case l_type. when 'DDLS'. try. cl_dd_ddl_handler_factory=&gt;create( )-&gt;read( exporting name = conv ddlname( to_upper( l_obj_name ) ) importing ddddlsrcv_wa = data(ddlsrcv_wa) ). catch cx_dd_ddl_read into data(exc). cl_demo_output=&gt;display( exc-&gt;get_text( ) ). endtry. if ddlsrcv_wa-source is initial. cl_demo_output=&gt;display( |Nothing found| ). return. endif. cl_demo_output=&gt;display( replace( val = ddlsrcv_wa-source sub = |\n| with = `` occ = 0 ) ). when others. *---get the source code (other then DDLS) read report l_obj_name into lt_source_cd. if sy-subrc eq 0. data(l_source_code) = reduce string( init lv_src type string *---Don't consider ANY commented code for lw_source in lt_source_cd index into lv_index where ( table_line+0(1) ne '*' ) next lv_src=to_upper( lv_src ) &amp;&amp; space &amp;&amp; to_upper( lw_source-src_cd ) &amp;&amp; | LINE#: { lv_index }#| ). clear lt_source_cd. data(l_search_pattern) = `(?:LINE#: (\d)+)(?=#[\w\s]+` &amp;&amp; |{ l_ddls }| &amp;&amp; `)`. data(lv_result) = match( val = l_source_code regex = l_search_pattern case = abap_false ). if lv_result is not initial. data(lv_line) = match( val = lv_result regex = `(?:LINE#:\s)([0-9]+)` case = abap_false ). split lv_line at ':' into data(l_part1) data(l_part2). condense l_part2 no-gaps. else. message |Object: { l_ddls }, has no direct usage| type 'S'. endif. endif. call function 'RS_TOOL_ACCESS' exporting operation = 'SHOW' object_name = l_obj_name object_type = l_type position = cond char10( when l_part2 = 0 then space else ( l_part2 + 1 ) ) exceptions not_executed = 1 invalid_object_type = 2 others = 3. if sy-subrc &lt;&gt; 0. * Implement suitable error handling here endif. endcase. endmethod. endclass. start-of-selection. * case abap_true. * * when p_rad1. * IF p_ddls1 IS INITIAL. if s_ddls1[] is initial. message 'Enter a CDS View to proceed!' type 'S'. leave list-processing. endif. loop at s_ddls1 into data(p_ddls1). w_ddls_f = '\TY:' &amp;&amp; p_ddls1-low. *---Find parent DDLS (if any) select * from ddls_ris_index into table (t_ddls_where_used) where used_artifact_fullname = @w_ddls_f. if sy-subrc eq 0. loop at t_ddls_where_used reference into data(lo_ddls). append initial line to t_ddls_w reference into data(lo_ddls_wu). split lo_ddls-&gt;used_artifact_fullname at ':' into data(w_part1) data(w_part2). lo_ddls_wu-&gt;ddls = w_part2. lo_ddls_wu-&gt;o_type = 'DDLS'. lo_ddls_wu-&gt;obj_name = lo_ddls-&gt;ddlsrc_name. endloop. endif. *----find all other ABAP Objects where input DDLS been used select name, include, case repo~subc when '1' then 'REPS' when 'K' then 'CLAS' when 'I' then 'INCL' when 'F' then 'FUGR' else 'UN' end as o_type from wbcrossgt as wb left outer join reposrc as repo on wb~include = repo~progname INTO table (lt_wbcrossgt) where otype = 'TY' and name = @p_ddls1-low and indirect = . if sy-subrc eq 0. sort lt_wbcrossgt by name include o_type. *---Check for Function Modules loop at lt_wbcrossgt reference into data(lo_wbcross) where o_type = 'UN'. append initial line to t_func reference into data(lo_func). lo_func-&gt;funcname = lo_wbcross-&gt;include. endloop. if t_func is not initial. select funcname, pname from tfdir INTO table (t_tfdir) for all entries in @t_func where funcname = @t_func-funcname. if sy-subrc eq 0. sort t_tfdir by funcname. endif. endif. loop at lt_wbcrossgt reference into lo_wbcross. append initial line to t_ddls_w reference into lo_ddls_wu. if lo_wbcross-&gt;o_type = 'UN' and line_exists( t_tfdir[ funcname = lo_wbcross-&gt;include ] ). lo_ddls_wu-&gt;ddls = p_ddls1. lo_ddls_wu-&gt;o_type = 'FUNC'. lo_ddls_wu-&gt;obj_name = lo_wbcross-&gt;include. else. lo_ddls_wu-&gt;ddls = p_ddls1. lo_ddls_wu-&gt;o_type = lo_wbcross-&gt;o_type. lo_ddls_wu-&gt;obj_name = lo_wbcross-&gt;include. endif. endloop. endif. append LINES OF t_ddls_w[] TO t_ddls_final[]. clear: t_ddls_w, t_func, t_tfdir. endloop. * WHEN OTHERS. * ** ** when p_rad2. ** message 'This feature, not yet Supported' type 'S'. ** leave list-processing. * endcase. * if t_ddls_w is not initial. if t_ddls_final[] is not initial. call method cl_salv_table=&gt;factory importing r_salv_table = data(lo_alv1) changing t_table = t_ddls_final[]. if lo_alv1 is bound. lo_alv1-&gt;get_functions( )-&gt;set_all( abap_true ). lo_alv1-&gt;get_columns( )-&gt;set_optimize( abap_true ). data(lo_evt_handler) = new lcl_event_handler( lo_alv1 ). data(lo_events) = lo_alv1-&gt;get_event( ). set handler lo_evt_handler-&gt;on_double_click for lo_events. lo_evt_handler-&gt;lt_alv = t_ddls_w. lo_alv1-&gt;display( ). endif. * else. * * message 'No records found!' type 'S'. * leave list-processing. * endif.</code></pre><P>&nbsp;</P><P>&nbsp;</P><P>There is no line by line explanation or comment because the code is self-explanatory. Talk less code more <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span>&nbsp;</P> 2025-06-26T10:31:12.615000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/i-built-langchain-lite-for-abap-and-solved-the-enterprise-ai-cold-start/ba-p/14140633 I Built LangChain-lite for ABAP, and Solved the Enterprise AI Cold Start Problem 2025-06-30T17:39:51.098000+02:00 Alice_V https://community.sap.com/t5/user/viewprofilepage/user-id/609259 <P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChatGPT Image Jun 30, 2025, 11_09_03 PM.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280949i0438743D88756A58/image-size/large?v=v2&amp;px=999" role="button" title="ChatGPT Image Jun 30, 2025, 11_09_03 PM.png" alt="ChatGPT Image Jun 30, 2025, 11_09_03 PM.png" /></span></P><H3 id="ember819" id="toc-hId-1863137963">Why enterprise AI projects fail at the "last mile"</H3><P class=""><STRONG>AGI has been achieved!</STRONG>* <EM>Now your ABAP-Native AI can reach enterprise data where it lives.</EM></P><HR /><P class="">Hello! <span class="lia-unicode-emoji" title=":waving_hand:">👋</span> It's Alice again, and I've spent the last 1.5 years building what I wish had existed when I started my AI journey: <STRONG>a complete LLM orchestration framework that lives entirely within SAP.</STRONG></P><H3 id="ember822" id="toc-hId-1666624458">TL;DR:</H3><UL><LI><STRONG>GitHub:</STRONG> oisee/zllm (releasing incrementally - link in first comment)</LI><LI><STRONG>Problem:</STRONG> Enterprise AI projects die in "integration hell" between proof-of-concept and production</LI><LI><STRONG>Solution:</STRONG> Native ABAP AI orchestration - no Python, no APIs, no middleware</LI><LI><STRONG>Result:</STRONG> Build production AI workflows in hours, not months</LI></UL><HR /><H3 id="ember824" id="toc-hId-1470110953">Remember my previous posts?</H3><UL><LI><P class=""><span class="lia-unicode-emoji" title=":magnifying_glass_tilted_left:">🔍</span><A class="" href="https://community.sap.com/t5/technology-blog-posts-by-members/vector-search-in-pure-abap-any-db/ba-p/13572298" target="_self"><STRONG>ZVDB</STRONG> </A>brought vector search to ABAP</P></LI><LI><P class=""><span class="lia-unicode-emoji" title=":straight_ruler:">📏</span><A class="" href="https://community.sap.com/t5/technology-blog-posts-by-members/predictoken-fast-local-token-count-prediction-for-abap-and-edge-devices/ba-p/14127977" target="_self"><STRONG>PREDICTOKEN</STRONG> </A>eliminated expensive tokenizer calls</P></LI><LI><P class=""><span class="lia-unicode-emoji" title=":link:">🔗</span><A class="" href="https://community.sap.com/t5/technology-blog-posts-by-members/universal-odata-mcp-bridge-or-how-i-accidentally-made-15-000-enterprise/ba-p/14134696" target="_self"><STRONG>The OData-MCP bridge </STRONG></A>connected 15,000+ enterprise services to AI</P></LI></UL><P>&nbsp;</P><P class="">Those were puzzle pieces; <STRONG>ZLLM is the complete picture.</STRONG></P><HR /><H3 id="ember827" id="toc-hId-1273597448">The "Last Mile" Problem Nobody Talks About</H3><P class="">Your AI proof-of-concept is <STRONG>brilliant</STRONG>. The CEO is <STRONG>excited</STRONG>. Then someone asks:</P><P class=""><EM>"When can we connect this to our actual SAP system?"</EM></P><P class=""><STRONG>Traditional Answer:</STRONG> "We need APIs, data pipelines, authentication, environments, deployments, monitoring..."</P><P class=""><STRONG>Six months later:</STRONG> Still in integration hell. <span class="lia-unicode-emoji" title=":skull:">💀</span></P><P class=""><STRONG>ZLLM Answer:</STRONG> "It's already connected." <span class="lia-unicode-emoji" title=":sparkles:">✨</span></P><HR /><H3 id="ember833" id="toc-hId-1077083943">What Enterprise AI Actually Looks Like</H3><P class="">This is what you can build <STRONG>today</STRONG>, in pure ABAP, with zero external dependencies:</P><PRE>" Complete customer intelligence pipeline DATA(lo_flow) = zcl_llm_00_flow_lazy=&gt;new( VALUE #( ( lo_extract_customer_data ) ( lo_analyze_behavior_patterns ) ( lo_identify_upsell_opportunities ) ( lo_generate_action_plan ) ( lo_update_crm_notes ) ) ). DATA(lr_result) = lo_flow-&gt;exec( REF #( lv_customer_id ) ).</PRE><P class="">Time to production: <STRONG>Hours </STRONG>External systems involved: <STRONG>Zero** </STRONG>Integration code: <STRONG>Zero</STRONG></P><HR /><H3 id="ember836" id="toc-hId-880570438">The Template Engine That Understands Your Data</H3><P class="">Here's where ZLLM gets <STRONG>magical</STRONG> - watch this:</P><PRE>" Your nested ABAP structure DATA: BEGIN OF ls_order, customer TYPE BEGIN OF customer_struct, name TYPE string, vip_status TYPE abap_bool, END OF customer, items TYPE TABLE OF order_item, END OF ls_order. " Template that just works DATA(lo_pattern) = zcl_llm_00_pat=&gt;new( 'Customer {T-CUSTOMER-NAME} (VIP: {T-CUSTOMER-VIP_STATUS}) ' &amp;&amp; 'ordered {T-ITEMS-PRODUCT_NAME} for ${T-ITEMS-PRICE}' ). DATA(lv_prompt) = lo_pattern-&gt;apply( REF #( ls_order ) ). </PRE><P class="">The template engine automatically:</P><P class="">&nbsp;</P><UL><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>Navigates deep structure hierarchies</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>Iterates over internal tables</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>Converts complex data to JSON when needed</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>Handles NULL values gracefully</LI></UL><P>&nbsp;</P><P class=""><STRONG>No JSON glue code. No data mapping. No field-by-field extraction. It just works.</STRONG></P><DIV class=""><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Alice_V_3-1751297799237.png" style="width: 920px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280736i3CC7CDBCC823F02F/image-dimensions/920x269?v=v2" width="920" height="269" role="button" title="Alice_V_3-1751297799237.png" alt="Alice_V_3-1751297799237.png" /></span><P>&nbsp;</P></DIV><HR /><H3 id="ember842" id="toc-hId-684056933">Lazy Execution: The Enterprise Performance Secret</H3><P class="">Traditional AI workflows block everything:</P><PRE># Traditional synchronous hell result1 = llm.call(prompt1) # Wait 3 seconds result2 = llm.call(prompt2) # Wait 3 seconds result3 = llm.call(prompt3) # Wait 3 seconds # Total: 9 seconds of blocking execution </PRE><P class="">ZLLM uses lazy execution for real performance:</P><PRE>" Start all operations immediately (non-blocking) DATA(lo_result1) = lo_step1-&gt;start( ir_input ). DATA(lo_result2) = lo_step2-&gt;start( ir_input ). DATA(lo_result3) = lo_step3-&gt;start( ir_input ). " Collect results when ready DATA(lr_final1) = lo_result1-&gt;collect( ). " ~3 seconds total </PRE><DIV class=""><DIV class=""><DIV class=""><P>&nbsp;</P></DIV></DIV></DIV><HR /><H3 id="ember846" id="toc-hId-487543428">The Security Story Enterprise Can Actually Use</H3><P class="">ZLLM includes security foundations that scale to enterprise requirements:</P><P class=""><STRONG>At Rest:</STRONG></P><PRE>" Default: Symmetric XOR with seed (fine for PoC/development) SET PARAMETER ID 'ZLLM_CODEC' FIELD '12345'. " Production: Implement your codec interface DATA(lo_enterprise_codec) = zcl_your_enterprise_codec=&gt;new( ). </PRE><P class=""><STRONG>At Runtime:</STRONG></P><PRE>" Inherits SAP's proven security model " If user can't access data in GUI, they can't access via AI " No new security surface area </PRE><P class=""><STRONG>Bottom Line:</STRONG> ZLLM starts secure enough for development and PoCs, with clear paths to enterprise-grade security when you need it.</P><HR /><H3 id="ember851" id="toc-hId-291029923">Real Demo: 30-Second Customer Intelligence</H3><PRE>METHOD generate_customer_intelligence. DATA(lo_extract) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Extract key purchasing patterns from: {T}' iv_sys = 'Return as structured JSON with trends' io_llm = lo_llm ). DATA(lo_opportunities) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Based on patterns {T}, identify 3 upsell opportunities' io_llm = lo_llm ). DATA(lo_flow) = zcl_llm_00_flow_lazy=&gt;new( VALUE #( ( lo_extract ) ( lo_opportunities ) ) ). DATA(ls_customer) = get_customer_patterns( iv_customer ). RETURN lo_flow-&gt;exec( REF #( ls_customer ) ). ENDMETHOD. </PRE><P class=""><STRONG>Result:</STRONG> SAP data → AI analysis → Business recommendations in 30 seconds.</P><HR /><H3 id="ember853" id="toc-hId-94516418">Load Balancing: Right Model, Right Cost</H3><PRE>" Smart routing based on complexity DATA(lo_llm_smart) = zcl_llm_00_llm_lazy_composite=&gt;new( io_llm = lo_llm_mini " Fast, cheap model io_llm_exp = lo_llm_maxi " Powerful, expensive model iv_threshold = 1000 " Token threshold ). " Simple queries → Mini model (fast + cheap) " Complex queries → Maxi model (powerful + expensive) </PRE><DIV class=""><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Alice_V_4-1751297838517.png" style="width: 585px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280737iD1A92BB912B3233E/image-dimensions/585x1013?v=v2" width="585" height="1013" role="button" title="Alice_V_4-1751297838517.png" alt="Alice_V_4-1751297838517.png" /></span><P>&nbsp;</P><DIV class=""><DIV class=""><P>&nbsp;</P></DIV></DIV></DIV><HR /><H3 id="ember856" id="toc-hId--177228456">PREDICTOKEN: The Secret Weapon</H3><PRE>" Predict tokens before expensive API calls DATA(lv_predicted_tokens) = zcl_llm_00_predictoken=&gt;predict_tokens_gpt4( lv_text ). IF lv_predicted_tokens &lt; 500. lo_llm = lo_llm_mini. " Cheap model ELSEIF lv_predicted_tokens &gt; 8000. lo_flow = lo_split_flow. " Split into multiple calls ENDIF. </PRE><P class=""><STRONG>Accuracy:</STRONG> 99.7% token prediction (R² &gt; 0.997 on 50,000+ validation samples) without API calls.</P><HR /><H3 id="ember858" id="toc-hId--373741961">One-Click Invoice Intelligence</H3><P class="">Complete invoice processing workflow:</P><PRE>DATA(lo_flow) = zcl_llm_00_flow_lazy=&gt;new( VALUE #( ( lo_extract_invoice_data ) ( lo_validate_against_po ) ( lo_flag_anomalies ) ( lo_generate_approval_routing ) ( lo_update_workflow_system ) ) ). " Process 1000 invoices in parallel DATA(lo_parallel) = zcl_llm_00_step_lazy_parallel=&gt;new( io_step = lo_flow-&gt;to_step( ) io_llm = lo_llm ). </PRE><HR /><H3 id="ember860" id="toc-hId--570255466">Getting Started: The 10-Minute Setup</H3><P class="">&nbsp;</P><OL><LI><STRONG>Run:</STRONG> ZLLM_00_ONBOARD - Configure your LLM endpoints</LI><LI><STRONG>Demo:</STRONG> ZLLM_00_FLOW_DEMO - See chaining in action</LI><LI><STRONG>Build:</STRONG> Your first workflow in pure ABAP</LI></OL><P>&nbsp;</P><PRE>DATA(lo_llm) = zcl_llm=&gt;new( 'DEFAULT.ENV' ). DATA(lo_step) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Analyze this data: {T}' io_llm = lo_llm ). DATA(lr_result) = lo_step-&gt;exec( REF #( your_business_data ) ). </PRE><HR /><H3 id="ember862" id="toc-hId--766768971">The "But What About..." Section</H3><P class=""><STRONG>"What about Python's rich AI ecosystem?"</STRONG> Over half of enterprise AI work is data movement, not algorithms. ZLLM excels at the majority use case.</P><P class=""><STRONG>"What about scaling?"</STRONG> SAP systems already handle your enterprise load. ZLLM scales with your existing infrastructure.</P><P class=""><STRONG>"What about vendor lock-in?"</STRONG> ZLLM actually <STRONG><EM>reduces </EM></STRONG>vendor lock-in. You can hot-swap your LLM including self-hosted Ollama - try this with Joule <span class="lia-unicode-emoji" title=":grinning_face_with_big_eyes:">😃</span></P><PRE># Monday: Local Ollama (zero vendor dependency) API_MODEL=codellama API_URL=http://localhost:11434/ API_KEY=ollama # Tuesday: Switch to Azure (same ABAP code) API_AZURE_FULL_URL=https://your-domain.openai.azure.com/... API_KEY=your-azure-key # Wednesday: Your own inference cluster API_MODEL=your-custom-model API_URL=http://your-internal-cluster/v1/ API_KEY=internal </PRE><P class="">One framework, any LLM provider. Change your .env file, restart your program. That's it.</P><P class="">Meanwhile, Joule ties you to whatever models SAP decides to support. ZLLM works with anything that speaks OpenAI API - including models that don't exist yet.</P><HR /><H3 id="ember868" id="toc-hId--963282476">Why This Changes Everything</H3><P class=""><STRONG>Before ZLLM:</STRONG> AI projects required new infrastructure, teams, security reviews, integration patterns, deployment processes.</P><P class=""><STRONG>After ZLLM:</STRONG> AI projects are ABAP development projects. Use existing everything.</P><P class="">The "cold start problem" disappears because there's no cold start. Your AI capabilities live where your business logic lives.</P><HR /><H3 id="ember872" id="toc-hId--1159795981">The Enterprise AI Future</H3><P class="">This isn't another AI framework. This is enterprise AI that makes business sense:</P><P class="">&nbsp;</P><UL><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>No integration projects</STRONG> - AI lives in your business logic</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>No new infrastructure</STRONG> - Use your existing SAP systems</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>No new security model</STRONG> - Inherit SAP's proven security</LI><LI><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>No new deployment process</STRONG> - Deploy like any ABAP development</LI></UL><P>&nbsp;</P><P class=""><STRONG>AGI* has been achieved.</STRONG> Now your ABAP can generate intelligence.</P><HR /><H3 id="ember876" id="toc-hId--1356309486">Ready to eliminate your AI integration hell?</H3><P class=""><span class="lia-unicode-emoji" title=":star:">⭐</span><STRONG>Star &amp; Fork</STRONG> on GitHub - Get early access to the framework</P><P class=""><STRONG>Comment below:</STRONG> What's your most painful SAP business process? Let's see how ZLLM can eliminate that pain.</P><P class="">Build in hours what took quarters—or never shipped—six months ago.</P><P class=""><EM>The ideal enterprise AI integration is one that doesn't exist because the capability is native:&nbsp;"<STRONG>we already have an LLM at home!</STRONG>"</EM></P><HR /><P class=""><STRONG>About the Author:</STRONG></P><P class="">Alice Vinogradova is a Senior Software Engineer with two decades of ABAP/SAP experience and a passion for practical AI integration. She specializes in eliminating complexity through innovation, bringing cutting-edge AI capabilities to conservative enterprise environments without the traditional integration overhead.</P><P class=""><STRONG>P.S.</STRONG> This framework exists because I got tired of explaining why enterprise AI projects fail. Better to build the solution than argue about the problem. ^_^</P><P class="">*<STRONG>ABAP Generative Intelligence <span class="lia-unicode-emoji" title=":grinning_face_with_big_eyes:">😃</span></STRONG></P><P class=""><STRONG>**No external API, except LLM of course.</STRONG></P><HR /><P class=""><STRONG>Hashtags:</STRONG> #SAP #ABAP #AI #EnterpriseAI #LLM #Innovation #TechLeadership #LangChain #ZLLM</P><P class=""><STRONG>N.B. It was just released and </STRONG>Lars Hvam&nbsp;already sent 5 pull-requests with bug fixes! Thanks a mil, Lars ^_^</P><P>&nbsp;</P> 2025-06-30T17:39:51.098000+02:00 https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-members/navigating-the-labyrinth-choosing-the-right-persistent-data-storage-for/ba-p/14133660 Navigating the Labyrinth: Choosing the Right Persistent Data Storage for Your Custom Development 2025-07-01T09:57:50.815000+02:00 vaibhav4 https://community.sap.com/t5/user/viewprofilepage/user-id/394709 <P>Hello All,</P><P>During a recent implementation project, I encountered a familiar yet significant dilemma: determining the right approach for <STRONG>persistent data storage in a custom RICEF development</STRONG>. The functional team specifically requested something as intuitive and user-friendly as <STRONG>SM30</STRONG> for data maintenance—a scenario many of us in the SAP ecosystem can relate to.</P><P>While the need for a custom configuration table was clear, the abundance of options in S/4HANA—across both on-premise and cloud environments—made the decision more complex than expected. Add to that the challenge of balancing legacy ECC practices with modern S/4HANA architecture, and the decision-making process becomes even more nuanced.</P><P>In this blog, I’ll walk through our real-world scenario, the solutions we considered, and the reasoning behind the final choice. The goal is to offer a concise yet practical guide to help others facing similar decisions in their S/4HANA journey.</P><P><SPAN><FONT size="4"><STRONG>Understanding the Landscape: On-Premise vs. Cloud</STRONG></FONT></SPAN></P><P><SPAN>Before we dive into the specifics, it's crucial to understand that the choice of approach is heavily influenced by your SAP S/4HANA deployment model: on-premise or cloud. The"clean core" strategy, which emphasizes upgrade stability and limiting direct modifications to the core system, significantly shapes the available options, especially in the public cloud. What might be a viable solution on-premise could be entirely unsupported or not recommended in the cloud.</SPAN></P><P><SPAN>Let's break down the options by deployment model.</SPAN></P><P><SPAN><FONT size="4"><STRONG>S/4HANA On-Premise: A Blend of Tradition and Modernity</STRONG></FONT><BR />In an S/4HANA on-premise environment, you have the flexibility to leverage both traditional ABAP development paradigms and newer, cloud-aligned approaches. This often leads to the dilemma that we faced: which path to take?<BR /></SPAN></P><P><SPAN><STRONG>1. The Classical ABAP Approach: The Tried and True (with a Caveat)</STRONG></SPAN></P><P><SPAN><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Classical ABAP Approach.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280030i668F9CA9EFD79072/image-size/large?v=v2&amp;px=999" role="button" title="Classical ABAP Approach.png" alt="Classical ABAP Approach.png" /></span><BR />This is perhaps the most familiar territory for many seasoned ABAP developers. It involves creating custom tables directly in the ABAP Dictionary (transaction SE11) and then generating a maintenance dialog using the Table Maintenance Generator (TMG) viaSE11 or SE54. End-users can then maintain data using the ubiquitous transaction SM30. You can even create custom transaction codes (SE93) for direct access, enhancing user experience and security. TMG also offers "events" where you can embed custom ABAP logic for validations, defaulting values, and other business requirements.</SPAN></P><P><STRONG>Features:</STRONG></P><UL><LI><STRONG>Full Control:&nbsp;</STRONG>You get granular control over table design, field properties, and database attributes. This is ideal for highly complex data models or scenarios requiring specific performance optimizations at the database level.</LI><LI><STRONG>Familiarity:&nbsp;</STRONG>SM30 is a standard and widely known transaction, making it familiar to many SAP users for data maintenance.</LI><LI><STRONG>Custom Logic:&nbsp;</STRONG>TMG events provide hooks for embedding custom ABAP logic, allowing for robust validations and business rules.</LI></UL><P><STRONG>When to Use:</STRONG></P><UL><LI>When maximum control and flexibility over table design and implementation are paramount.</LI><LI>For highly complex data models or specific performance optimizations that can only be achieved at the ABAP Dictionary level.</LI><LI>When existing SAP GUI-based processes are acceptable or preferred by the end-users, or when the development effort for a Fiori UI is not justified for the specific use case.</LI></UL><P><STRONG>2. The Custom TVARVC Table Approach: Simple Configurations, Simple Maintenance</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Custom TVARVC Table Approach.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280031i4AB90CA95F7C3C93/image-size/large?v=v2&amp;px=999" role="button" title="Custom TVARVC Table Approach.png" alt="Custom TVARVC Table Approach.png" /></span></STRONG></P><P>This approach involves creating a custom table (typically starting with 'Z' or 'Y') that mimics the structure of the standard TVARVC table. This custom table is then used to store application-specific parameters or simple configuration values. Maintenance is usually performed via Custom SAP GUI report/ transactions similar to STVARV or SM30.</P><P><STRONG>Features:</STRONG></P><UL><LI><STRONG>Simple Configuration:&nbsp;</STRONG>Ideal for storing key-value pairs or simple ranges, such as company codes, plant-specific parameters, threshold values, or lists for custom logic. It's excellent for preventing hardcoding of values in ABAP programs, userexits, and reports.</LI><LI><STRONG>Reusable Framework:</STRONG> A single custom TVARVC-style table and its supporting maintenance report can be designed as a reusable framework, enabling consistent configuration handling across multiple custom developments.</LI></UL><P><STRONG>When to Use:</STRONG></P><UL><LI>For simple configuration parameters that control custom ABAP developments.</LI><LI>When a quick and straightforward solution with minimal initial development for table structure and maintenance UI is needed.</LI><LI>When end-users are comfortable with SAP GUI for configuration maintenance.</LI></UL><P><STRONG>3. Custom Business Objects (CBOs): The Modern On-Premise Approach</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Custom Business Objects.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280032iDFD36D26B8B249FA/image-size/large?v=v2&amp;px=999" role="button" title="Custom Business Objects.png" alt="Custom Business Objects.png" /></span></STRONG></P><P>Custom Business Objects (CBOs) represent a modern and increasingly recommended method for defining custom data structures and behaviors in S/4HANA on-premise. They are managed via the "Custom Business Objects" Fiori app. A significant advantage of CBOs is the automatic generation of a Fiori-based UI for data maintenance, eliminating the need for manual UI development for basic CRUD operations. Each CBO is backed by a system-provisioned database table and inherently exposes an OData service for seamless integration with Fiori applications and other systems. This is essentially a low-code approach to custom tables with integrated Fiori maintenance.</P><P><STRONG>Features:</STRONG></P><UL><LI><STRONG>Automatic Fiori UI:</STRONG>&nbsp;The system automatically generates a Fiori-based UI for data maintenance, providing a modern user experience with minimal development effort.</LI><LI><STRONG>OData Service Exposure:</STRONG>&nbsp;CBOs automatically expose an OData service, simplifying integration with other Fiori apps, SAP systems, and external applications.</LI><LI><STRONG>Key User Extensibility:</STRONG>&nbsp;CBOs empower key users to define and manage their owndata structures through a Fiori interface, reducing reliance on traditional ABAP developers for simple requirements.</LI><LI><STRONG>Associations and Logic:</STRONG>&nbsp;Supports associations with other business objects for intricate data models and allows for custom logic (validations, determinations) via cloud BAdIs.</LI></UL><P><STRONG>When to Use:</STRONG></P><UL><LI>When the primary requirement is a user-friendly, modern Fiori interface for custom table maintenance.</LI><LI>For rapid development and deployment of maintenance UIs with minimal coding.</LI><LI>Well-suited for moderately complex data structures.</LI><LI>When you want to empower key users with extensibility capabilities.</LI></UL><P><STRONG>4. Fiori Elements with ABAP RESTful Application Programming Model(RAP): The Future of On-Premise Development</STRONG></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Fiori Elements.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280033iD3F230F083B478F8/image-size/large?v=v2&amp;px=999" role="button" title="Fiori Elements.png" alt="Fiori Elements.png" /></span></STRONG></P><P>This is a powerful and increasingly recommended approach for building Fiori applications, including those for custom table maintenance, in S/4HANA on-premise.RAP provides a standardized way to build OData services for transactional and analytical applications. Fiori Elements then automatically generate UIs based on these OData services and CDS views, significantly accelerating development.</P><P><STRONG>Features:</STRONG></P><UL><LI><STRONG>Model-Driven UI:&nbsp;</STRONG>Fiori Elements generate UIs automatically from CDS views andOData services, drastically reducing manual UI coding.</LI><LI><STRONG>RAP for Backend Logic:</STRONG>&nbsp;RAP handles the transactional and analytical logic,including CRUD operations for custom tables, ensuring a robust and scalablebackend.</LI><LI><STRONG>Integrated Development:</STRONG>&nbsp;Development is done in ADT (ABAP Development Toolsin Eclipse), providing a modern development experience.</LI></UL><P><STRONG>When to Use:</STRONG></P><UL><LI>When building new Fiori applications for custom table maintenance in S/4HANA on-premise.</LI><LI>For scenarios requiring a robust, scalable, and performant solution that aligns with SAP's strategic direction.</LI><LI>When you want to leverage the benefits of automated UI generation and a consistent Fiori user experience.</LI></UL><P><STRONG>5. Freestyle SAPUI5 Applications: Ultimate UI Customization</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Freestyle SAPUI5.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280034i387E4328A4B16ABD/image-size/large?v=v2&amp;px=999" role="button" title="Freestyle SAPUI5.png" alt="Freestyle SAPUI5.png" /></span><BR />For scenarios requiring highly customized user interfaces or complex interactions not easily achievable with Fiori Elements or CBOs, developers can build freestyle SAPUI5applications. These applications consume OData services (often built using classical ABAP or RAP) that expose the custom table data.</P><P><STRONG>Features:</STRONG></P><UL><LI><STRONG>Full UI Control:</STRONG>&nbsp;Developers have complete control over the UI layout, controls, and behavior, allowing for unique branding, complex data entry forms, or highly interactive dashboards.</LI><LI><STRONG>Flexibility:</STRONG>&nbsp;Allows for highly specific UI/UX requirements that go beyond standard Fiori Elements templates.</LI><LI><STRONG>Data Binding:</STRONG>&nbsp;Connects to backend data via OData services, which can be built using classical ABAP (SEGW) or RAP.</LI></UL><P><STRONG>When to Use:</STRONG></P><UL><LI>When your UI/UX requirements are extremely unique, complex, or cannot be met by standard Fiori Elements or CBO-generated UIs.</LI><LI>For highly interactive applications that require a bespoke user experience.</LI></UL><P><STRONG>On-Premise Summary: Choosing the Right Persistent Storage Method</STRONG></P><P>&nbsp; &nbsp;</P><TABLE><TBODY><TR><TD width="171px"><STRONG>Approach</STRONG></TD><TD width="133px"><STRONG>UI Type</STRONG></TD><TD width="110px"><STRONG>Who Builds</STRONG></TD><TD width="103px"><STRONG>&nbsp;Coding Required</STRONG></TD><TD width="158px"><STRONG>Clean Core Alignment</STRONG></TD><TD width="270px"><STRONG>Best Use Case</STRONG></TD></TR><TR><TD width="171px">Classical ABAP (SM30)</TD><TD width="133px">SAP GUI (SM30)</TD><TD width="110px">Developers</TD><TD width="103px">Medium</TD><TD width="158px"><span class="lia-unicode-emoji" title=":cross_mark:">❌</span>Low</TD><TD width="270px">Legacy compatibility, complex tables, TMG event handling</TD></TR><TR><TD width="171px">Custom TVARVC Table</TD><TD width="133px">SAP GUI (STVARV/SM30)</TD><TD width="110px">Developers</TD><TD width="103px">Low</TD><TD width="158px"><span class="lia-unicode-emoji" title=":cross_mark:">❌</span>Low</TD><TD width="270px">Simple config parameters, fast implementation</TD></TR><TR><TD width="171px">Custom Business Objects (CBOs)</TD><TD width="133px">Fiori (Auto-generated)</TD><TD width="110px">Key Users / Devs</TD><TD width="103px">Low to Medium</TD><TD width="158px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>High</TD><TD width="270px">Rapid deployment of Fiori-based maintenance apps</TD></TR><TR><TD width="171px">RAP + Fiori Elements</TD><TD width="133px">Fiori (Auto-generated)</TD><TD width="110px">Developers</TD><TD width="103px">Medium to High</TD><TD width="158px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>High</TD><TD width="270px">Modern architecture, scalable, maintainable development</TD></TR><TR><TD width="171px">Freestyle SAPUI5 App</TD><TD width="133px">Fiori (Custom UI)</TD><TD width="110px">Developers</TD><TD width="103px">High</TD><TD width="158px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>High&nbsp;</TD><TD width="270px">Highly customized UI/UX, complex workflows or dashboards</TD></TR></TBODY></TABLE><P>&nbsp;</P><P><FONT size="4"><STRONG>S/4HANA Cloud: The "Clean Core" Paradigm</STRONG></FONT></P><P><FONT size="4"><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="s4 hana cloud.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/280035i854D6F9F7B161B3D/image-size/large?v=v2&amp;px=999" role="button" title="s4 hana cloud.png" alt="s4 hana cloud.png" /></span></STRONG></FONT></P><P>In SAP S/4HANA Cloud (Public Edition), custom development follows strict <STRONG>“clean core”</STRONG> principles—minimizing direct system modifications to ensure upgrade stability. Traditional ABAP methods like SM30 or TVARVC-based tables are not applicable due to the absence of SAP GUI and limited backend extensibility.</P><P>Instead, SAP provides modern, cloud-compliant extensibility options:</P><H4 id="toc-hId-1991386624">1. <STRONG>Custom Business Objects (CBOs): Key User-Friendly and Fiori-Ready</STRONG></H4><P>CBOs are the recommended way to handle custom data needs in the cloud. Created via the <EM>"Custom Business Objects"</EM> Fiori app, they support:</P><UL><LI><P><STRONG>Auto-generated Fiori UI</STRONG> for maintenance (CRUD)</P></LI><LI><P><STRONG>Automatic OData exposure</STRONG> for integration</P></LI><LI><P><STRONG>No-code/low-code development</STRONG> suited for business users</P></LI><LI><P><STRONG>Upgrade-safe</STRONG> by design</P></LI></UL><P><STRONG>Use When:</STRONG> You need a quick, compliant way to store and maintain custom data with minimal developer effort.</P><HR /><H4 id="toc-hId-1794873119">2. <STRONG>ABAP Cloud (Embedded Steampunk) + RAP: For Pro Developers</STRONG></H4><P>For advanced scenarios, ABAP Cloud (via Embedded Steampunk) allows professional developers to build applications using <STRONG>RAP</STRONG> within ADT. These apps:</P><UL><LI><P>Use <STRONG>whitelisted APIs</STRONG> and <STRONG>restricted ABAP syntax</STRONG></P></LI><LI><P>Expose <STRONG>OData services</STRONG> for consumption in Fiori Elements</P></LI><LI><P>Are <STRONG>fully aligned with clean core</STRONG> standards</P></LI></UL><P><STRONG>Use When:</STRONG> You need full control over backend logic or have complex business scenarios beyond what key user tools offer.</P><HR /><H4 id="toc-hId-1598359614">3. <STRONG>Custom SAPUI5 on BTP: For Bespoke UI Requirements</STRONG></H4><P>For highly customized or interactive UIs, build SAPUI5 apps on <STRONG>SAP BTP</STRONG>, consuming OData services from RAP or CBOs.</P><P><STRONG>Use When:</STRONG> Standard Fiori templates don’t meet your UX needs and you want to keep extensions <STRONG>side-by-side</STRONG> (not inside the core).</P><HR /><H3 id="toc-hId-1272763390">Summary</H3><DIV class=""><DIV class="">&nbsp; &nbsp; &nbsp; <TABLE><TBODY><TR><TD width="154px"><STRONG>Approach</STRONG></TD><TD width="96px"><STRONG>UI Type</STRONG></TD><TD width="93px"><STRONG>Who Builds</STRONG></TD><TD width="128px"><STRONG>Coding Required</STRONG></TD><TD width="192px"><STRONG>Clean Core Compliance</STRONG></TD><TD width="282px"><STRONG>Use Case</STRONG></TD></TR><TR><TD width="154px">CBO</TD><TD width="96px">Auto Fiori UI</TD><TD width="93px">Key Users</TD><TD width="128px">No/Low</TD><TD width="192px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>High</TD><TD width="282px">Simple to moderate custom data needs</TD></TR><TR><TD width="154px">RAP + Fiori Elements</TD><TD width="96px">Auto Fiori UI</TD><TD width="93px">Developers</TD><TD width="128px">Yes</TD><TD width="192px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>High</TD><TD width="282px">Complex business logic, developer-led</TD></TR><TR><TD width="154px">SAPUI5 on BTP</TD><TD width="96px">Custom UI</TD><TD width="93px">Developers</TD><TD width="128px">Yes</TD><TD width="192px"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span>Very High (Side-by-side)</TD><TD width="282px">Bespoke UX or standalone apps</TD></TR></TBODY></TABLE></DIV></DIV><P>&nbsp;</P><P><FONT size="5"><STRONG>Making the Right Choice: A Decision Framework</STRONG></FONT></P><P>Choosing the right approach for persistent data storage in your custom RICEF development is a critical decision that impacts development effort, user experience,integration capabilities, performance, security, transportability, and long-term maintainability. To simplify this, consider the following decision framework:</P><P><STRONG>1. Deployment Model First:</STRONG>&nbsp;Are you on S/4HANA On-Premise or S/4HANA Cloud(Public Edition)? This is the most crucial differentiator. Cloud environments are far more restrictive due to the "clean core" strategy.</P><P><STRONG>2. User Experience Requirement:</STRONG>&nbsp;Do your users require a traditional SAP GUI experience (less common now), a modern Fiori app experience, or a highly customized, bespoke UI?</P><P><STRONG>3. Data Model Complexity:&nbsp;</STRONG>Is your custom data simple (key-value pairs), moderately complex (multiple fields, simple associations), or highly complex (intricate relationships, specific performance needs)?</P><P><STRONG>4. Development Effort &amp; Skills:</STRONG>&nbsp;What are your team's existing skills (classical ABAP,RAP, SAPUI5, BTP) and what is the available development budget and timeline?</P><P><STRONG>5. "Clean Core" Adherence:</STRONG>&nbsp;How strictly do you need to adhere to the "clean core"principles for future upgrades and cloud readiness?</P><P>Here's a simplified table to guide your decision:</P><P>&nbsp;</P><TABLE border="1" width="100%"><TBODY><TR><TD width="16.666666666666668%" height="112px"><STRONG>Feature/Consideration</STRONG></TD><TD width="16.666666666666668%" height="112px"><STRONG>Classical ABAP(On-Premise)</STRONG></TD><TD width="16.666666666666668%" height="112px"><STRONG>Custom TVARVC (On-Premise)</STRONG></TD><TD width="16.666666666666668%" height="112px"><STRONG>CBOs (On-Premise &amp;Cloud)</STRONG></TD><TD width="16.666666666666668%" height="112px"><STRONG>RAP/Fiori Elements(On-Premise &amp;Cloud)</STRONG></TD><TD width="16.666666666666668%" height="112px"><STRONG>FreestyleUI5 (On-Premise &amp;Cloud)</STRONG></TD></TR><TR><TD width="16.666666666666668%" height="85px">Deployment</TD><TD width="16.666666666666668%" height="85px">On-Premise</TD><TD width="16.666666666666668%" height="85px">On-Premise</TD><TD width="16.666666666666668%" height="85px">On-Premise &amp;Cloud</TD><TD width="16.666666666666668%" height="85px">On-Premise &amp;Cloud</TD><TD width="16.666666666666668%" height="85px">On-Premise &amp;Cloud</TD></TR><TR><TD width="16.666666666666668%" height="85px">UI Type<BR />SAP</TD><TD width="16.666666666666668%" height="85px">SAP GUI(SM30)</TD><TD width="16.666666666666668%" height="85px">SAP GUI(STVARV/SM30)</TD><TD width="16.666666666666668%" height="85px">Fiori(Auto-generated)</TD><TD width="16.666666666666668%" height="85px">Fiori(Auto-generated)</TD><TD width="16.666666666666668%" height="85px">Fiori(Custom)</TD></TR><TR><TD width="16.666666666666668%" height="57px">Data Complexity</TD><TD width="16.666666666666668%" height="57px">High</TD><TD width="16.666666666666668%" height="57px">Low</TD><TD width="16.666666666666668%" height="57px">Medium</TD><TD width="16.666666666666668%" height="57px">High</TD><TD width="16.666666666666668%" height="57px">High</TD></TR><TR><TD width="16.666666666666668%" height="30px">Dev Effort</TD><TD width="16.666666666666668%" height="30px">Medium</TD><TD width="16.666666666666668%" height="30px">Low</TD><TD width="16.666666666666668%" height="30px">Medium</TD><TD width="16.666666666666668%" height="30px">Medium</TD><TD width="16.666666666666668%" height="30px">High</TD></TR><TR><TD width="16.666666666666668%" height="57px">"Clean Core"Alignment</TD><TD width="16.666666666666668%" height="57px">Low</TD><TD width="16.666666666666668%" height="57px">Low</TD><TD width="16.666666666666668%" height="57px">High</TD><TD width="16.666666666666668%" height="57px">High</TD><TD width="16.666666666666668%" height="57px">High(especially via BTP)</TD></TR><TR><TD width="16.666666666666668%" height="30px">Key User Extensibility</TD><TD width="16.666666666666668%" height="30px">No</TD><TD width="16.666666666666668%" height="30px">No</TD><TD width="16.666666666666668%" height="30px">Yes</TD><TD width="16.666666666666668%" height="30px">No(Developer)</TD><TD width="16.666666666666668%" height="30px">No(Developer)</TD></TR><TR><TD width="16.666666666666668%" height="30px">OData Exposure</TD><TD width="16.666666666666668%" height="30px">Manual(SEGW)</TD><TD width="16.666666666666668%" height="30px">No</TD><TD width="16.666666666666668%" height="30px">Automatic</TD><TD width="16.666666666666668%" height="30px">Automatic</TD><TD width="16.666666666666668%" height="30px">Consumes OData</TD></TR><TR><TD width="16.666666666666668%" height="30px">Best For</TD><TD width="16.666666666666668%" height="30px">Legacy, complex DB needs</TD><TD width="16.666666666666668%" height="30px">Simple config</TD><TD width="16.666666666666668%" height="30px">Rapid Fiori apps</TD><TD width="16.666666666666668%" height="30px">Robust Fiori apps,complex logic</TD><TD width="16.666666666666668%" height="30px">Unique UI/UX needs</TD></TR></TBODY></TABLE><P><FONT size="4"><STRONG>Final Thoughts</STRONG></FONT></P><P><FONT size="3">The world of SAP S/4HANA is constantly evolving, and so too are the best practices for custom development. The days of a one-size-fits-all approach are long gone. As ABAP developers and consultants, it's our responsibility to guide our functional colleagues and project teams towards the most appropriate and future-proof solutions.</FONT></P><P><FONT size="3">My recent experience reminded me that while the technical options are abundant, the real challenge lies in understanding the business requirement, the system landscape,and the long-term implications of each choice. By carefully considering the factors outlined above, you can navigate this labyrinth with confidence, ensuring your custom RICEF developments are not only functional but also scalable, maintainable, and aligned with SAP's strategic direction.</FONT></P><P><FONT size="3">Happy coding, and may your custom tables always be clean and performant!</FONT></P> 2025-07-01T09:57:50.815000+02:00 https://community.sap.com/t5/technology-blog-posts-by-sap/rap-transactional-app-performance-considerations-for-singleton-pattern-in/ba-p/14140680 RAP Transactional app: performance considerations for singleton pattern in draft enabled RAP BO 2025-07-01T11:50:32.505000+02:00 patrick_winkler https://community.sap.com/t5/user/viewprofilepage/user-id/729521 <H1 id="toc-hId-1604972677">Introduction</H1><P>When developing a transactional app, you can use the <A href="https://help.sap.com/docs/abap-cloud/abap-rap/developing-transactional-apps-with-multi-inline-edit-capabilities" target="_blank" rel="noopener noreferrer">singleton pattern for a draft enabled RAP BO</A> to enable editing / inline create on the actual root entity.</P><P>In this blog, you will learn how the singleton pattern impacts performance and other advantages and disadvantages of this pattern in the context of Fiori elements.</P><P>This blog is relevant for</P><UL><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+S%25252F4HANA+Cloud+Public+Edition/pd-p/08e2a51b-1ce5-4367-8b33-4ae7e8b702e0" target="_blank">SAP S/4HANA Cloud Public Edition</A></LI><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+S%25252F4HANA+Cloud+Private+Edition/pd-p/5c26062a-9855-4f39-8205-272938b6882f" target="_blank">SAP S/4HANA Cloud Private Edition</A><SPAN>&nbsp;</SPAN>&nbsp;</LI><LI><A class="" href="https://community.sap.com/t5/c-khhcw49343/SAP+BTP+ABAP+environment/pd-p/73555000100800001164" target="_blank">SAP BTP ABAP environment</A><SPAN>&nbsp;</SPAN>&nbsp;</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-1408459172">Example BO</H1><P>Our data model consists of a table T1 and a corresponding text table T1_TXT.</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Tab1' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #C @AbapCatalog.dataMaintenance : #ALLOWED define table T1 { key client : abap.clnt not null; key k1 : zpw_d1 not null; f1 : abap.char(20); f2 : abap.char(20); f3 : abap.char(20); f4 : abap.char(20); f5 : abap.char(20); f6 : abap.char(20); f7 : abap.char(20); f8 : abap.char(20); last_changed_at : abp_lastchange_tstmpl; local_last_changed_at : abp_locinst_lastchange_tstmpl; }</code></pre><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Tab1 Text' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #C @AbapCatalog.dataMaintenance : #ALLOWED define table T1_TXT { key client : abap.clnt not null; key langu : abap.lang not null; @AbapCatalog.foreignKey.keyType : #TEXT_KEY @AbapCatalog.foreignKey.screenCheck : false key k1 : zpw_d1 not null with foreign key T1 where client = T1_TXT.client and k1 = T1_TXT.k1; description : abap.char(30); local_last_changed_at : abp_locinst_lastchange_tstmpl; }</code></pre><P>Therefore, the draft-enabled RAP BO with singleton pattern consists of the singleton root entity type, T1 entity type, and T1_TXT entity type, each with a draft table.</P><H1 id="toc-hId-1211945667">Singleton draft</H1><P>When the <A href="https://help.sap.com/docs/abap-cloud/abap-rap/runtime-edit-action" target="_blank" rel="noopener noreferrer">Edit action</A> is performed on a root entity, a corresponding draft entity including all subentities is created. In the singleton pattern, this basically means that a draft entity is created for all entities of the RAP BO.<BR />Typically, the Edit action is performed when the user clicks the Edit button in the Fiori elements app. You can also use the following ABAP EML statement:</P><pre class="lia-code-sample language-abap"><code>MODIFY ENTITY zi_t1_s EXECUTE edit FROM VALUE #( ( %cid = |CID1| singletonid = 1 ) ). COMMIT ENTITIES.</code></pre><P>For our example BO, the Edit action therefore consists of three SQL statements in the form of INSERT INTO &lt;draft table&gt; SELECT FROM &lt;entity type cds view&gt;. No data is passed to the ABAP application server, only one statement per entity type, regardless of the number of entities.</P><P>The following measurement was performed in an ABAP Platform performance test system with respect to the above SQL statements as total:</P><TABLE border="1" width="100%"><TBODY><TR><TD width="25%">#Rows T1</TD><TD width="25%">#Rows T1_TXT</TD><TD width="25%">HANA CPU time [ms]</TD><TD width="25%">HANA max memory consumption [mb]</TD></TR><TR><TD width="25%">10</TD><TD width="25%">40</TD><TD width="25%">7</TD><TD width="25%">1</TD></TR><TR><TD width="25%">100</TD><TD width="25%">400</TD><TD width="25%">75</TD><TD width="25%">3</TD></TR><TR><TD width="25%">1000</TD><TD width="25%">4000</TD><TD width="25%">135</TD><TD width="25%">6</TD></TR><TR><TD width="25%">10000</TD><TD width="25%">40000</TD><TD width="25%">810</TD><TD width="25%">45</TD></TR><TR><TD width="25%">100000</TD><TD width="25%">400000</TD><TD width="25%">7600</TD><TD width="25%">437</TD></TR></TBODY></TABLE><P>This table shows the performance impact of the singleton pattern compared to a RAP BO without a singleton pattern. It is linear, so you can extrapolate for a higher number of lines.</P><P>If you use ABAP EML to modify entities, you do not need to create a draft entity, so this penalty does not necessarily apply to ABAP EML statements.</P><P data-unlink="true">The runtime behavior when changing a draft entity or in the <A href="https://help.sap.com/docs/abap-cloud/abap-rap/runtime-prepare-action" target="_blank" rel="noopener noreferrer">action prepare</A>&nbsp;is not affected by the singleton pattern.</P><P>During the <A href="https://help.sap.com/docs/abap-cloud/abap-rap/draft-action-activate-optimized" target="_blank" rel="noopener noreferrer">activation action</A>, the draft entities are discarded using a DELETE statement:</P><TABLE border="1" width="100%"><TBODY><TR><TD width="25%" height="57px">#Rows T1</TD><TD width="25%" height="57px">#Rows T1_TXT</TD><TD width="25%" height="57px">HANA CPU time [ms]</TD><TD width="25%" height="57px">HANA max memory consumption [mb]</TD></TR><TR><TD width="25%" height="30px">10</TD><TD width="25%" height="30px">40</TD><TD width="25%" height="30px">7</TD><TD width="25%" height="30px">1</TD></TR><TR><TD width="25%" height="30px">100</TD><TD width="25%" height="30px">400</TD><TD width="25%" height="30px">7</TD><TD width="25%" height="30px">2</TD></TR><TR><TD width="25%" height="30px">1000</TD><TD width="25%" height="30px">4000</TD><TD width="25%" height="30px">27</TD><TD width="25%" height="30px">4</TD></TR><TR><TD width="25%" height="30px">10000</TD><TD width="25%" height="30px">40000</TD><TD width="25%" height="30px">155</TD><TD width="25%" height="30px">10</TD></TR><TR><TD height="30px">100000</TD><TD height="30px">400000</TD><TD height="30px">430</TD><TD height="30px">43</TD></TR></TBODY></TABLE><P>So you can add this to the performance impact.</P><P>Logically, these numbers depend on the table and CDS view design as well as the system. But the basic statement remains.</P><P>If the user changes more than about 10% of the entities in the interaction phase, the singleton pattern is more performant because draft entities do not always have to be created.</P><H1 id="toc-hId-1015432162">Singleton in Fiori Elements</H1><P>Using a singleton RAP BO pattern in Fiori elements has the following characteristics:</P><UL><LI>Multi-line edit/inline creation for the actual root entity</LI><LI>The app can temporarily store global information in the singleton draft entity</LI><LI>All entities of the RAP BO are locked for a user</LI><LI>You cannot use selection fields as the <A href="https://sapui5.hana.ondemand.com/sdk/#/topic/4bd7590569c74c61a0124c6e370030f6.html" target="_blank" rel="noopener nofollow noreferrer">filter bar</A> is only available in the list report. Alternatively, you can add <A href="https://help.sap.com/docs/abap-cloud/abap-rap/adding-search-capabilities" target="_blank" rel="noopener noreferrer">search capabilities</A> to the entity. A search field is then available&nbsp;</LI></UL><P>See <A href="https://community.sap.com/t5/technology-blog-posts-by-sap/how-to-create-a-fiori-elements-app-for-a-rap-bo-with-transport-selection/ba-p/13562792" target="_blank">link</A> on how to create a Fiori Elements app for a RAP BO with singleton pattern.</P><H1 id="toc-hId-818918657">Custom Business Configurations</H1><P>When you create business configurations app using the ABAP RAP programming model, you use the&nbsp;<A href="https://help.sap.com/docs/sap-btp-abap-environment/abap-environment/creating-business-configuration-apps-with-abap-restful-application-programming-model-and-custom-business-configurations-app" target="_blank" rel="noopener noreferrer">Custom Business Configurations</A> app and the <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">business configuration maintenance object ADT wizard</A>.</P><P>The RAP BO that this wizard generates always uses the singleton pattern for the following reasons:</P><UL><LI>For configuration tables, you want to have a spreadsheet like user experience</LI><LI>The customizing transport request can be selected once for all entities and stored in the singleton draft entity</LI><LI>Locking the entire configuration for only one user is beneficial. You do not want multiple users to work on the same configuration table in parallel</LI><LI>The performance penalty for the singleton pattern is acceptable because<BR /><UL><LI>Configuration tables rarely have more than 1000 rows, let alone more than 10000 rows</LI><LI>Most of the configuration takes place in the intended system/client, not in the production client</LI><LI>The frequency of configuration changes is low</LI><LI>There is no performance impact when using ABAP EML or the <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/upload-business-configuration?version=Cloud" target="_blank" rel="noopener noreferrer">Upload Business Configurations</A> app</LI></UL></LI></UL><P>The Custom Business Configurations app also supports RAP BO without singleton pattern:</P><OL><LI>Create the RAP BO / Service binding without using the business configuration maintenance object ADT wizard</LI><LI>Add the relevant transport related functionality to the RAP BO</LI><LI>Create the business configuration maintenance object (SMBC) manually. Leave the option "Skip root entity list report" unchecked</LI></OL><H1 id="toc-hId-622405152">Conclusion</H1><P>Do not use the singleton pattern if the RAP BO handles more than 50000 entities and the app is used frequently.</P><P>&nbsp;</P> 2025-07-01T11:50:32.505000+02:00 https://community.sap.com/t5/technology-blog-posts-by-sap/customer-amp-partner-roundtable-for-sap-btp-abap-environment-25/ba-p/14141705 Customer & Partner Roundtable for SAP BTP ABAP Environment #25 2025-07-01T15:05:16.176000+02:00 iwona_hahn https://community.sap.com/t5/user/viewprofilepage/user-id/4326 <H3 id="toc-hId-1860394371" id="toc-hId-1863168624"><STRONG><SPAN class="lia-unicode-emoji"><SPAN class="lia-unicode-emoji"><span class="lia-unicode-emoji" title=":backhand_index_pointing_right:">👉</span></SPAN></SPAN>&nbsp;The call for contributions for one of the upcoming roundtables is open!&nbsp;</STRONG></H3><P>&nbsp;</P><DIV><TABLE><TBODY><TR><TD>If you want to show a demo or share a use case scenario for SAP BTP ABAP Environment send us an<SPAN>&nbsp;</SPAN><A href="mailto:sap_btp_abap_environment@sap.com" target="_blank" rel="noopener nofollow noreferrer">email</A>&nbsp;and we will get back to you.</TD></TR></TBODY></TABLE><SPAN>&nbsp;</SPAN></DIV><H2 id="toc-hId-1534798147" id="toc-hId-1537572400">Introduction</H2><P>&nbsp;</P><DIV><SPAN class="">A</SPAN><SPAN class="">s<SPAN>&nbsp;</SPAN></SPAN><A href="https://www.sap.com/products/technology-platform/abap/environment.html" target="_blank" rel="noopener noreferrer"><SPAN class="">SAP&nbsp;BTP&nbsp;ABAP&nbsp;environment (aka Steampunk)</SPAN><SPAN>&nbsp;</SPAN></A>and ABAP Cloud<SPAN>&nbsp;</SPAN><SPAN class="">became&nbsp;</SPAN><SPAN class="">more popular</SPAN><SPAN class=""><SPAN>&nbsp;</SPAN>inside and outside of SAP, there is a high demand for rolling out the latest product news and updates, asking questions, and showing demos.&nbsp;</SPAN><BR /><BR /><SPAN class="lia-unicode-emoji"><SPAN class="lia-unicode-emoji"><span class="lia-unicode-emoji" title=":light_bulb:">💡</span></SPAN></SPAN>&nbsp;You can find the slides presented, recordings, and further references from the previous roundtables in this<SPAN>&nbsp;</SPAN><A href="https://github.com/iwonahahn/SAP-BTP-ABAP-Environment-Roundtable/tree/main" target="_blank" rel="noopener nofollow noreferrer">GitHub repository</A>.<BR /><BR /></DIV><DIV><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="iwona_hahn_0-1751374366410.jpeg" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281320iF5290A011527C9B9/image-size/medium?v=v2&amp;px=400" role="button" title="iwona_hahn_0-1751374366410.jpeg" alt="iwona_hahn_0-1751374366410.jpeg" /></span><H2 id="toc-hId-1338284642" id="toc-hId-1341058895">Meeting Information<BR /><BR /></H2><STRONG>When:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</STRONG><BR /><UL><LI><STRONG><SPAN class="">July 31</SPAN></STRONG>, 10:00 - 11:00 AM CEST&nbsp; –<SPAN>&nbsp;</SPAN><A href="https://sap-se.zoom.us/meeting/register/YSluZpM6RzSFPhnydLjP8g" target="_blank" rel="nofollow noopener noreferrer">Zoom Meeting</A>&nbsp;(<STRONG>please register</STRONG><SPAN>&nbsp;</SPAN>in advance)&nbsp;</LI></UL></DIV><DIV>&nbsp;</DIV><DIV><STRONG>Who:</STRONG><UL><LI>All interested&nbsp;<STRONG>customers, partners,</STRONG>&nbsp;and&nbsp;<STRONG>stakeholders</STRONG>&nbsp;are invited to join this roundtable</LI><LI><STRONG>BTP ABAP team</STRONG>:<UL class="lia-list-style-type-circle"><LI><A href="https://community.sap.com/t5/user/viewprofilepage/user-id/4296" target="_blank">Frank Jentsch</A>&nbsp;<SPAN class="">(Product Lead for SAP BTP ABAP&nbsp;Environment)</SPAN></LI><LI><A href="https://community.sap.com/t5/user/viewprofilepage/user-id/4326" target="_self"><SPAN class="">Iwona Hahn</SPAN></A>&nbsp;<SPAN class="">(BTP ABAP Product Management)<BR /><BR /></SPAN></LI></UL></LI><LI><STRONG><SPAN class="">Partner<SPAN>&nbsp;<A href="https://www.blue-zone.io/en/" target="_blank" rel="noopener nofollow noreferrer">blue-zone GmbH</A></SPAN></SPAN></STRONG><SPAN class="">:&nbsp;</SPAN><UL class="lia-list-style-type-circle"><LI><SPAN class="">Andreas Klose&nbsp;</SPAN><SPAN class="">(Director Software Development)</SPAN></LI><LI><SPAN class=""><SPAN>Christof Unterste (Solution Architect)&nbsp;</SPAN></SPAN></LI></UL></LI></UL></DIV><DIV><STRONG><BR />Preliminary Agenda:</STRONG><BR /><UL><LI>Product update for SAP BTP ABAP Environment</LI><LI>Partner live demo:&nbsp;<SPAN class=""><A href="https://www.blue-zone.io/en/products/edi-zone/" target="_blank" rel="noopener nofollow noreferrer">EDI-ZONE</A> (EDI &amp; eInvoicing Solution) - managed SaaS solution on SAP BTP ABAP Environment:&nbsp; subaccount handling, customer onboarding etc.</SPAN></LI><LI>Q&amp;A&nbsp;</LI></UL><SPAN>Looking forward to meeting you!</SPAN></DIV><DIV>&nbsp;</DIV><DIV><A href="https://sap-se.zoom.us/meeting/register/YSluZpM6RzSFPhnydLjP8g" target="_blank" rel="noopener nofollow noreferrer"><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="iwona_hahn_1-1751374366424.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281321i39537B5D388BE6C4/image-size/medium?v=v2&amp;px=400" role="button" title="iwona_hahn_1-1751374366424.png" alt="iwona_hahn_1-1751374366424.png" /></span></A><P>&nbsp;</P><BR /><BR /><SPAN>Check out our</SPAN><SPAN>&nbsp;</SPAN><A href="https://pages.community.sap.com/topics/btp-abap-environment" target="_blank" rel="noopener noreferrer">SAP Business Technology ABAP Environment</A><SPAN>&nbsp;page in SAP Community&nbsp;</SPAN><SPAN>for&nbsp;</SPAN><SPAN>product&nbsp;</SPAN><SPAN>updates&nbsp;</SPAN><SPAN>and&nbsp;</SPAN><SPAN>upcoming events.</SPAN></DIV> 2025-07-01T15:05:16.176000+02:00 https://community.sap.com/t5/application-development-and-automation-blog-posts/side-effects-in-rap-explained-with-determination-example/ba-p/14140206 Side Effects in RAP Explained with Determination Example 2025-07-02T10:28:03.987000+02:00 Pradeep555 https://community.sap.com/t5/user/viewprofilepage/user-id/1451114 <P><SPAN>In the world of SAP RAP (RESTful Application Programming), Determinations and Side Effects play a crucial role in delivering responsive and intelligent user experiences. While determinations are used to implement logic that reacts to changes in data during specific RAP phases (such as </SPAN><SPAN>on modify</SPAN><SPAN> or </SPAN><SPAN>on save)</SPAN><SPAN>, side effects ensure that related fields or entities stay consistent and updated on the UI without additional user actions.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>In his blog, I will demonstrate a practical scenario where determinations are used to dynamically calculate&nbsp;</SPAN><SPAN>values based on user input, and side effects are configured to immediately reflect these changes on the UI. This not only improves the data integrity but also enhances usability in Fiori applications. By the end of this post, you will have a clearer understanding of how to leverage determinations and side effects together effectively within a RAP-based application.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>DETERMINATION :</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Actions modifies the existing BO instance where as Determination modifies the existing BO instances based on some&nbsp; trigger condition&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>We can see that Actions also triggers based on the conditions but cannot modify the BO instances , we can be able to throw the error messages.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>Pre requisites :</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>During modification we change/modify&nbsp; some fields / requirements&nbsp; and we can compute the values of&nbsp; particular fields</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Determination can be called during&nbsp; Transactional phase/Save sequence where as validations always called during the save sequence</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Once a determination&nbsp; has been triggered , it must run independently from other determinations</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>During determination result must change if we execute detrmination several time under same condition&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>Scenario :</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Here the determination calculateTotalPrice which is defined for all the three entities</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>(Travel, booking and booking supplements) handles the&nbsp; calculation of total&nbsp; price of one travel.</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Based on the booking Fee total price must be calculated for the travel&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>SIDE-EFFECTS:</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>The SAP Fiori UI does not necessarily trigger a reload of all&nbsp; related BO after every User input , as it simply does not know anything </SPAN><SPAN>about data changes&nbsp; on the tables</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Side effects are&nbsp; used to reload data, permissions or messages based on data changes in UI scenarios with draft enabled BO’s&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Side effects reloads the screen but it does not reload entire screen&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>&nbsp;It changes some of the field values or will enable/ disable some of the fied values&nbsp;&nbsp;&nbsp; Or status of the data in transactional buffer --&gt; based on these same things should appear in the front end&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>We need to define side effects in Behaviour definition&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Side effects will only reload the fields in front end&nbsp; ,nothing will happen in backend&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>The data which is available in the backend it will reload in the front end whihc is not currently displaying properly</SPAN> <SPAN>&nbsp;</SPAN></LI></UL><P>&nbsp;</P><P><SPAN>Side effects have two parts :</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Triggering condition : specifies when you should reload ( can be actions / validations)</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Target : which fields should get&nbsp; reloaded ( value of a field / multiple fields / reload entire entity )</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P>&nbsp;</P><P><SPAN>Important points:</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Determinations calculates the total&nbsp; price and updates it into the transcational buffer</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>But in the front end screen older values will be there .</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>Requirement :</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Whenever I change the booking fee and booking supplement data and flight price</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>The total&nbsp; price should be updated not only in transactional buffer but also in the front end automatically&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>And whenever we are updating booking fee the reload of total price should happen&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Based on the trigger condition --&gt; it should reload the values / fields&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;</SPAN></P><P><SPAN>Here the source --&gt; Booking fee</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Target --&gt; totalprice</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>Syntax:</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Side effects { filed MyField affects Target }</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { $self affects Targets ; }</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { action MyAction affects Tragets ;}</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp;&nbsp; { determine action MyDetermineAction&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp; Executed on sources&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Affects Tagets } .</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>In the target we can specify :</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>$self : The current RAP BO is reloaded&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Entity _MyAssoc&nbsp; : the specified associated entity&nbsp; _MyAssoc is reloaded when the side effect is triggered&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>Message&nbsp; : all the messages in the response parameter reported are reloaded when the side effects is triggered&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>We can&nbsp; also als provide multiple targets&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>&nbsp;</SPAN></P><P><SPAN>Side effects { field MyField affects Field1 , Field2 , action Action1 ,</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Action Action 2 [..] }</SPAN><SPAN>&nbsp;</SPAN></P><P>&nbsp;</P><P><SPAN>RESTRICTIONS :</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Static actions&nbsp; defined using the addition static must&nbsp; not be used as a side effect trigger , nor as a side effect target&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>In case of the trigger entity property $sefl , the target cannot be a field of the current entity $self itself ,&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>However fields&nbsp; from the associated entity can be defined using path&nbsp; expressions&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;</SPAN></P><P><SPAN>Side Effect In BDL:</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Side effects can be specified exactly once for each RAP BO entity in the entity&nbsp;</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P><SPAN>Behaviour definition&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><UL><LI><SPAN>Multiple side effects can&nbsp; be summarized with curly brackets , separated by a semicolon (; ) , if required.</SPAN><SPAN>&nbsp;</SPAN></LI></UL><UL><LI><SPAN>The syntax ‘use side effects’ is specified in the behaviour definition header and all&nbsp; side effects from all&nbsp; RAP BO entities of the underlying RAP BO are reused</SPAN><SPAN>&nbsp;</SPAN></LI></UL><P>&nbsp;</P><P><SPAN>1.&nbsp;<SPAN class=""><SPAN class="">Create </SPAN><SPAN class="">db</SPAN><SPAN class=""> table for travel&nbsp;</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'travel table' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zpd_dt_travel { key client : abap.clnt not null; key travel_id : /dmo/travel_id not null; agency_id : /dmo/agency_id; customer_id : /dmo/customer_id; begin_date : /dmo/begin_date; end_date : /dmo/end_date; @Semantics.amount.currencyCode : 'zpd_dt_travel.currency_code' booking_fee : /dmo/booking_fee; @Semantics.amount.currencyCode : 'zpd_dt_travel.currency_code' total_price : /dmo/total_price; currency_code : /dmo/currency_code; description : /dmo/description; overall_status : /dmo/overall_status; created_by : abp_creation_user; created_at : abp_creation_tstmpl; last_changed_by : abp_locinst_lastchange_user; last_changed_at : abp_locinst_lastchange_tstmpl; } </code></pre><P>2.<SPAN><SPAN class=""><SPAN class="">Create </SPAN><SPAN class="">db</SPAN><SPAN class=""> table for Booking</SPAN></SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'tbale for booking details' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zpd_dt_booking { key client : abap.clnt not null; @AbapCatalog.foreignKey.label : 'Travel' @AbapCatalog.foreignKey.screenCheck : false key travel_id : /dmo/travel_id not null with foreign key [0..*,1] zpd_dt_travel where travel_id = zpd_dt_booking.travel_id; key booking_id : /dmo/booking_id not null; booking_date : /dmo/booking_date; customer_id : /dmo/customer_id; carrier_id : /dmo/carrier_id; connection_id : /dmo/connection_id; flight_date : /dmo/flight_date; @Semantics.amount.currencyCode : 'zpd_dt_booking.currency_code' flight_price : /dmo/flight_price; currency_code : /dmo/currency_code; booking_status : /dmo/booking_status; last_changed_at : abp_locinst_lastchange_tstmpl; } </code></pre><P><SPAN><SPAN class=""><SPAN class="">&nbsp;3.Crete a db table for Booking suppliment</SPAN></SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'booking supplimnet' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zpd_dt_bsupplmnt { key client : abap.clnt not null; @AbapCatalog.foreignKey.label : 'Travel' @AbapCatalog.foreignKey.screenCheck : false key travel_id : /dmo/travel_id not null with foreign key [0..*,1] zpd_dt_travel where travel_id = zpd_dt_bsupplmnt.travel_id; @AbapCatalog.foreignKey.label : 'Booking' @AbapCatalog.foreignKey.screenCheck : false key booking_id : /dmo/booking_id not null with foreign key [0..*,1] zpd_dt_booking where travel_id = zpd_dt_bsupplmnt.travel_id and booking_id = zpd_dt_bsupplmnt.booking_id; key booking_supplement_id : /dmo/booking_supplement_id not null; supplement_id : /dmo/supplement_id; @Semantics.amount.currencyCode : 'zpd_dt_bsupplmnt.currency_code' price : /dmo/supplement_price; currency_code : /dmo/currency_code; last_changed_at : abp_locinst_lastchange_tstmpl; } </code></pre><P><SPAN><SPAN class="">&nbsp;4.Create a root view entity for travel</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'root view for travel' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define root view entity zi_travel_detail as select from zpd_dt_travel composition [0..*] of ZI_BOOKING_DETAIL as _booking association [0..1] to /DMO/I_Agency as _agency on $projection.AgencyId = _agency.AgencyID association [0..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID association [1..1] to I_Currency as _currency on $projection.CurrencyCode = _currency.Currency association [1..1] to /DMO/I_Overall_Status_VH as _status on $projection.OverallStatus = _status.OverallStatus { key travel_id as TravelId, agency_id as AgencyId, customer_id as CustomerId, begin_date as BeginDate, end_date as EndDate, @Semantics.amount.currencyCode: 'CurrencyCode' booking_fee as BookingFee, @Semantics.amount.currencyCode: 'CurrencyCode' total_price as TotalPrice, currency_code as CurrencyCode, description as Description, overall_status as OverallStatus, @Semantics.user.createdBy: true created_by as CreatedBy, @Semantics.systemDateTime.createdAt: true created_at as CreatedAt, @Semantics.user.localInstanceLastChangedBy: true last_changed_by as LastChangedBy, @Semantics.systemDateTime.localInstanceLastChangedAt: true last_changed_at as LastChangedAt, _agency, _customer, _currency, _status, _booking } </code></pre><P><SPAN><SPAN class="">5.Create interface view&nbsp; for booking&nbsp;</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'root view for booking' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define view entity ZI_BOOKING_DETAIL as select from zpd_dt_booking association to parent zi_travel_detail as _travel on $projection.TravelId = _travel.TravelId composition [0..*] of zi_booking_supp as _bookingsuppl association [1..1] to /DMO/I_Carrier as _carrier on $projection.CarrierId = _carrier.AirlineID association [1..1] to /DMO/I_Customer as _customer on $projection.CustomerId = _customer.CustomerID association [1..1] to /DMO/I_Connection as _connection on $projection.CarrierId = _connection.AirlineID and $projection.ConnectionId = _connection.ConnectionID association[1..1] to /DMO/I_Booking_Status_VH as _booking_status on $projection.BookingStatus = _booking_status.BookingStatus { key travel_id as TravelId, key booking_id as BookingId, booking_date as BookingDate, customer_id as CustomerId, carrier_id as CarrierId, connection_id as ConnectionId, flight_date as FlightDate, @Semantics.amount.currencyCode: 'CurrencyCode' flight_price as FlightPrice, currency_code as CurrencyCode, booking_status as BookingStatus, @Semantics.systemDateTime.localInstanceLastChangedAt: true last_changed_at as LastChangedAt, _carrier, _customer, _connection, _booking_status, _travel, _bookingsuppl } </code></pre><P>6.Create Interface view for Booking suppliment</P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'root view for booking suppliment' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define view entity zi_booking_supp as select from zpd_dt_bsupplmnt association to parent ZI_BOOKING_DETAIL as _booking on $projection.TravelId = _booking.TravelId and $projection.BookingId = _booking.BookingId association[1..1] to zi_travel_detail as _travel on $projection.TravelId = _travel.TravelId association [1..1] to /DMO/I_Supplement as _suppliment on $projection.SupplementId = _suppliment.SupplementID association[1..*] to /DMO/I_SupplementText as _supplimentText on $projection.SupplementId = _supplimentText.SupplementID { key travel_id as TravelId, key booking_id as BookingId, key booking_supplement_id as BookingSupplementId, supplement_id as SupplementId, @Semantics.amount.currencyCode: 'CurrencyCode' price as Price, currency_code as CurrencyCode, @Semantics.systemDateTime.localInstanceLastChangedAt: true last_changed_at as LastChangedAt, _travel, _supplimentText, _suppliment, _booking } </code></pre><P>7.<SPAN class=""><SPAN class="">Define projection for travel root entity</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'consumption view for travel' @Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true define root view entity zc_travel_det provider contract transactional_query as projection on zi_travel_detail { key TravelId, @ObjectModel.text.element: [ 'AgencyName' ] AgencyId, _Agency.Name as AgencyName, @ObjectModel.text.element: [ 'CustomerName' ] CustomerId, _Customer.LastName as CustomerName, BeginDate, EndDate, @Semantics.amount.currencyCode: 'CurrencyCode' BookingFee, @Semantics.amount.currencyCode: 'CurrencyCode' TotalPrice, CurrencyCode, Description, @ObjectModel.text.element: [ 'OverallStatusText' ] OverallStatus, _Status._Text.Text as OverallStatusText : localized, CreatedBy, CreatedAt, LastChangedBy, LastChangedAt, /* Associations */ _Agency, _booking : redirected to composition child zc_booking_det, _Currency, _Customer, _Status } </code></pre><P><SPAN>&nbsp;8.<SPAN class=""><SPAN class="">Define projection for booking&nbsp; entity</SPAN></SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'consumption view for booking' @Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true define view entity zc_booking_det as projection on ZI_BOOKING_DETAIL { key TravelId, key BookingId, BookingDate, @ObjectModel.text.element: [ 'CustomerName' ] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Customer', element: 'CustomerID' } }] CustomerId, _customer.LastName as CustomerName, @ObjectModel.text.element: [ 'CarrierName' ] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Carrier', element: 'AirlineId' } }] CarrierId, _carrier.Name as CarrierName, @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Flight', element: 'Connection Id' } }] ConnectionId, FlightDate, @Semantics.amount.currencyCode: 'CurrencyCode' FlightPrice, CurrencyCode, @ObjectModel.text.element: [ 'BookingStatusText' ] _booking_status._Text.Text as BookingStatusText : localized, @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Booking_Status_VH', element: 'Booking_Status' } }] BookingStatus, LastChangedAt, /* Associations */ _bookingsuppl : redirected to composition child zc_booking_supp, _booking_status, _carrier, _connection, _customer, _travel : redirected to parent zc_travel_det } </code></pre><P>9.<SPAN><SPAN class="">Define projection for booking&nbsp; suppliment&nbsp; entity</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'consumption view for booking suppliment' @Metadata.ignorePropagatedAnnotations: true @Metadata.allowExtensions: true define view entity zc_booking_supp as projection on zi_booking_supp { key TravelId, key BookingId, key BookingSupplementId, @ObjectModel.text.element: [ 'SupplemenDesc' ] SupplementId, _SupplementText.Description as SupplemenDesc : localized, @Semantics.amount.currencyCode: 'CurrencyCode' Price, CurrencyCode, LastChangedAt, /* Associations */ _Travel : redirected to zc_travel_det, _Booking : redirected to parent zc_booking_det, _Supplement, _SupplementText } </code></pre><P>10.provide metada extension for projected views</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE @Search.searchable: true @UI.headerInfo: { typeName: 'Travel', typeNamePlural: 'Travels', title: { type: #STANDARD, label: 'Travel', value: 'TravelId' } } annotate view zc_travel_det with { @UI.facet: [{ id: 'Travel', purpose: #STANDARD, position: 10 , label: 'Travel', type: #IDENTIFICATION_REFERENCE }, { id: 'Booking', purpose: #STANDARD, position: 20 , label: 'Booking', type: #LINEITEM_REFERENCE, targetElement: '_booking' } ] @UI.lineItem: [{ position: 10 }, { type:#FOR_ACTION, dataAction: 'CopyTravel', label: 'Copy Travel' } ,{ type:#FOR_ACTION, dataAction: 'AcceptTravel', label: 'AcceptTravel' } ,{ position: 30 },{ type:#FOR_ACTION, dataAction: 'RejectTravel', label: 'RejectTravel' }] @UI.identification: [{ position: 10 }] @Search.defaultSearchElement: true TravelId; @UI: { lineItem: [{ position: 40 }], selectionField: [{ position: 40 }], identification: [{ position: 40 }] } @Search.defaultSearchElement: true @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Agency', element: 'AgencyID' } }] AgencyId; // AgencyName; @UI: { lineItem: [{ position: 50 }], selectionField: [{ position: 50 }], identification: [{ position: 50 }] } @Search.defaultSearchElement: true @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Customer', element: 'CustomerID' } }] CustomerId; // CustomerName; @UI.lineItem: [{ position: 60 }] @UI.identification: [{ position: 60 }] BeginDate; @UI.lineItem: [{ position: 70 }] @UI.identification: [{ position: 70 }] EndDate; @UI.identification: [{ position: 75 }] BookingFee; @UI.lineItem: [{ position: 80 }] @UI.identification: [{ position: 80 }] TotalPrice; @Consumption.valueHelpDefinition: [{ entity: { name: 'I_Currency', element: 'Currency' } }] CurrencyCode; @UI.identification: [{ position: 85 }] Description; @UI: { lineItem: [{ position: 90 }], selectionField: [{ position: 60 }], identification: [{ position: 90 }], textArrangement: #TEXT_ONLY } @Search.defaultSearchElement: true @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Overall_Status_VH', element: 'OverallStatus' } }] OverallStatus; // OverallStatusText; // .hidden: true // LastChangedAt; } </code></pre><P>11. metadata extension for booking entity</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE @Search.searchable: true @UI.headerInfo: { typeName: 'Booking', typeNamePlural: 'Bookings', title: { type: #STANDARD, label: 'Booking', value: 'BookingId' } } annotate view zc_booking_det with { @UI.facet: [{ id: 'Booking', purpose: #STANDARD, position: 10 , label: 'Booking', type: #IDENTIFICATION_REFERENCE }, { id: 'BookingSuppl', purpose: #STANDARD, position: 20 , label: 'Booking Suppliments', type: #LINEITEM_REFERENCE, targetElement: '_bookingsuppl' } ] // .defaultSearchElement: true // TravelId; @UI.lineItem: [{ position: 10 }] @UI.identification: [{ position: 10 }] @Search.defaultSearchElement: true BookingId; @UI.lineItem: [{ position: 20 }] @UI.identification: [{ position: 20 }] BookingDate; @UI.lineItem: [{ position: 30 }] @UI.identification: [{ position: 30 }] @Search.defaultSearchElement: true @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Customer', element: 'CustomerID' } }] CustomerId; @UI.lineItem: [{ position: 40 }] @UI.identification: [{ position: 40 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Carrier', element: 'AirlineID' } }] CarrierId; @UI.lineItem: [{ position: 50 }] @UI.identification: [{ position: 50 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Flight', element: 'ConnectionId' }, additionalBinding: [{ element: 'ConnectionId' , localElement: 'ConnectionID'}, { element: 'AirlineID' , localElement: 'CarrierId'}, { element: 'CurrencyCode' , localElement: 'CurrencyCode'}, { element: 'Price' , localElement: 'FlightPrice'} ] }] ConnectionId; @UI.lineItem: [{ position: 60 }] @UI.identification: [{ position: 60 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Flight', element: 'FlightDate' }, additionalBinding: [{ element: 'FlightDate' , localElement: 'FlightDate'}, { element: 'AirlineID' , localElement: 'CarrierId'}, { element: 'CurrencyCode' , localElement: 'CurrencyCode'}, { element: 'Price' , localElement: 'FlightPrice'} ] }] FlightDate; @UI.lineItem: [{ position: 70 }] @UI.identification: [{ position: 70 }] FlightPrice; // @Consumption.valueHelpDefinition: [{ entity: { // name: 'I_Currency', // element: 'Currency' // } }] // CurrencyCode; @UI.lineItem: [{ position: 80 }] @UI.identification: [{ position: 80 }] @UI.textArrangement: #TEXT_ONLY @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Booking_Status_VH', element: 'BookingStatus' } }] BookingStatus; // LastChangedAt; } </code></pre><P>12. Metadata extension for booking entity</P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CORE @Search.searchable: true @UI.headerInfo: { typeName: 'Booking', typeNamePlural: 'Bookings', title: { type: #STANDARD, label: 'Booking', value: 'BookingId' } } annotate view zc_booking_det with { @UI.facet: [{ id: 'Booking', purpose: #STANDARD, position: 10 , label: 'Booking', type: #IDENTIFICATION_REFERENCE }, { id: 'BookingSuppl', purpose: #STANDARD, position: 20 , label: 'Booking Suppliments', type: #LINEITEM_REFERENCE, targetElement: '_bookingsuppl' } ] // .defaultSearchElement: true // TravelId; @UI.lineItem: [{ position: 10 }] @UI.identification: [{ position: 10 }] @Search.defaultSearchElement: true BookingId; @UI.lineItem: [{ position: 20 }] @UI.identification: [{ position: 20 }] BookingDate; @UI.lineItem: [{ position: 30 }] @UI.identification: [{ position: 30 }] @Search.defaultSearchElement: true @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Customer', element: 'CustomerID' } }] CustomerId; @UI.lineItem: [{ position: 40 }] @UI.identification: [{ position: 40 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Carrier', element: 'AirlineID' } }] CarrierId; @UI.lineItem: [{ position: 50 }] @UI.identification: [{ position: 50 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Flight', element: 'ConnectionId' }, additionalBinding: [{ element: 'ConnectionId' , localElement: 'ConnectionID'}, { element: 'AirlineID' , localElement: 'CarrierId'}, { element: 'CurrencyCode' , localElement: 'CurrencyCode'}, { element: 'Price' , localElement: 'FlightPrice'} ] }] ConnectionId; @UI.lineItem: [{ position: 60 }] @UI.identification: [{ position: 60 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Flight', element: 'FlightDate' }, additionalBinding: [{ element: 'FlightDate' , localElement: 'FlightDate'}, { element: 'AirlineID' , localElement: 'CarrierId'}, { element: 'CurrencyCode' , localElement: 'CurrencyCode'}, { element: 'Price' , localElement: 'FlightPrice'} ] }] FlightDate; @UI.lineItem: [{ position: 70 }] @UI.identification: [{ position: 70 }] FlightPrice; // @Consumption.valueHelpDefinition: [{ entity: { // name: 'I_Currency', // element: 'Currency' // } }] // CurrencyCode; @UI.lineItem: [{ position: 80 }] @UI.identification: [{ position: 80 }] @UI.textArrangement: #TEXT_ONLY @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_Booking_Status_VH', element: 'BookingStatus' } }] BookingStatus; // LastChangedAt; } </code></pre><P>&nbsp;13.&nbsp;Metadata extension for booking&nbsp; suppliment entity</P><PRE>@Metadata.layer: #CORE @Search.searchable: true @UI.headerInfo: { typeName: 'BookingSuppl', typeNamePlural: 'BookingSuppls', title: { type: #STANDARD, label: 'Booking Suppliments', value: 'BookingSupplementId' } } annotate view zc_booking_supp with { @UI.facet: [{ id: 'BookingSuppl', purpose: #STANDARD, position: 10 , label: 'Booking Suppliments', type: #IDENTIFICATION_REFERENCE } ] // @Search.defaultSearchElement: true // TravelId; @Search.defaultSearchElement: true BookingId; @UI.lineItem: [{ position: 10 }] @UI.identification: [{ position: 10 }] BookingSupplementId; @UI.lineItem: [{ position: 20 }] @UI.identification: [{ position: 20 }] @Consumption.valueHelpDefinition: [{ entity: { name: '/DMO/I_SUPPLEMENT', element: 'SupplementID' }, additionalBinding: [{ element: 'SupplementID' , localElement: 'SupplementId'}, { element: 'Price' , localElement: 'Price'}, { element: 'CurrencyCode' , localElement: 'CurrencyCode'} ] }] SupplementId; @UI.lineItem: [{ position: 30 }] @UI.identification: [{ position: 30 }] Price; // @Consumption.valueHelpDefinition: [{ entity: { // name: 'I_Currency', // element: 'Currency' // } }] // CurrencyCode; // @UI.hidden: true // LastChangedAt; } </PRE><P>14.&nbsp;<SPAN class=""><SPAN class="">Create</SPAN><SPAN class=""> behaviour definition travel root entity</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>managed; strict ( 2 ); define behavior for zi_travel_detail //alias &lt;alias_name&gt; implementation in class zcl_bp_travel_maa unique persistent table zpd_dt_travel lock master authorization master ( global ) etag master LastChangedAt early numbering { field ( readonly ) TravelId; action AcceptTravel result [1] $self; action RejectTravel result [1] $self; factory action CopyTravel [1]; internal action RecalcTotalPrice; determination CalcTotalPrice on modify { create; field BookingFee, CurrencyCode; } // authorization ( global ), create; update; delete; // field ( readonly ) TravelId; association _booking { create; } mapping for zpd_dt_travel { TravelId = travel_id; AgencyId = agency_id; CustomerId = customer_id; BeginDate = begin_date; EndDate = end_date; BookingFee = booking_fee; TotalPrice = total_price; CurrencyCode = currency_code; Description = description; OverallStatus = overall_status; CreatedBy = created_by; CreatedAt = created_at; LastChangedBy = last_changed_by; LastChangedAt = last_changed_at; } } define behavior for ZI_BOOKING_DETAIL //alias &lt;alias_name&gt; implementation in class zcl_bp_booking_ma unique persistent table zpd_dt_booking lock dependent by _Travel //authorization dependent by _travel authorization master ( global ) etag master LastChangedAt early numbering { update; delete; field ( readonly ) TravelId, BookingId; determination CalcTotalPrice on modify { create; field FlightPrice, CurrencyCode; } association _travel; association _bookingsuppl { create; } mapping for zpd_dt_booking { TravelId = travel_id; BookingId = booking_id; BookingDate = booking_date; CustomerId = customer_id; CarrierId = carrier_id; ConnectionId = connection_id; FlightDate = flight_date; FlightPrice = flight_price; CurrencyCode = currency_code; BookingStatus = booking_status; LastChangedAt = last_changed_at; } } define behavior for zi_booking_supp //alias &lt;alias_name&gt; implementation in class zcl_bp_booking_ma unique persistent table zpd_dt_bsupplmnt lock dependent by _Travel //authorization dependent by _Travel authorization master ( global ) etag master LastChangedAt early numbering { update; delete; field ( readonly ) TravelId, BookingId, BookingSupplementId; determination CalcTotalPrice on modify { create; field Price, CurrencyCode; } association _Travel; association _Booking; mapping for zpd_dt_bsupplmnt { SupplementId = supplement_id; TravelId = travel_id; BookingId = booking_id; BookingSupplementId = booking_supplement_id; Price = price; CurrencyCode = currency_code; LastChangedAt = last_changed_at; } } </code></pre><P>15.&nbsp;<SPAN class=""><SPAN class="">Define </SPAN><SPAN class="">behavior definition</SPAN><SPAN class=""> for projection root entity</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>projection; strict ( 2 ); define behavior for zc_travel_det //alias &lt;alias_name&gt; { use create; use update; use delete; use action AcceptTravel; use action RejectTravel; use action CopyTravel; use association _booking { create; } } define behavior for zc_booking_det //alias &lt;alias_name&gt; { use update; use delete; use association _travel; use association _bookingsuppl { create; } } define behavior for zc_booking_supp //alias &lt;alias_name&gt; { use update; use delete; use association _Travel; use association _Booking; } </code></pre><P>16. Create Service Definition</P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'service def for travel' define service Zsr_travel_det { expose zc_travel_det; expose zc_booking_det; expose zc_booking_supp; expose /DMO/I_Supplement_StdVH as Supplement; expose /DMO/I_SupplementCategory_VH as SupplementCategory; expose /DMO/I_Customer_StdVH as Passenger; expose /DMO/I_Agency_StdVH as TravelAgency; expose /DMO/I_Carrier_StdVH as Airline; expose /DMO/I_Connection_StdVH as FlightConnection; expose /DMO/I_Flight_StdVH as Flight; expose /DMO/I_Airport_StdVH as Airport; expose /DMO/I_Overall_Status_VH as OverallStatus; expose /DMO/I_Booking_Status_VH as BookingStatus; expose I_CurrencyStdVH as Currency; expose I_CountryVH as Country; } </code></pre><P>17.&nbsp;<SPAN class=""><SPAN class="">Create service binding</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_0-1751354700486.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281015iFEA8DEFC3496780A/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_0-1751354700486.png" alt="Pradeep555_0-1751354700486.png" /></span></P><P>18. Implement the class&nbsp;</P><pre class="lia-code-sample language-abap"><code>CLASS lhc_zi_travel_detail DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION IMPORTING REQUEST requested_authorizations FOR zi_travel_detail RESULT result. METHODS accepttravel FOR MODIFY IMPORTING keys FOR ACTION zi_travel_detail~accepttravel RESULT result. METHODS copytravel FOR MODIFY IMPORTING keys FOR ACTION zi_travel_detail~copytravel. METHODS recalctotalprice FOR MODIFY IMPORTING keys FOR ACTION zi_travel_detail~recalctotalprice. METHODS rejecttravel FOR MODIFY IMPORTING keys FOR ACTION zi_travel_detail~rejecttravel RESULT result. METHODS calctotalprice FOR DETERMINE ON MODIFY IMPORTING keys FOR zi_travel_detail~calctotalprice. METHODS earlynumbering_cba_booking FOR NUMBERING IMPORTING entities FOR CREATE zi_travel_detail\_booking. METHODS earlynumbering_create FOR NUMBERING IMPORTING entities FOR CREATE zi_travel_detail. ENDCLASS. CLASS lhc_zi_travel_detail IMPLEMENTATION. METHOD get_global_authorizations. ENDMETHOD. METHOD earlynumbering_create. DATA(lt_entities) = entities. DELETE lt_entities WHERE TravelId IS NOT INITIAL . TRY. cl_numberrange_runtime=&gt;number_get( EXPORTING nr_range_nr = '01' object = '/DMO/TRV_M' quantity = CONV #( lines( lt_entities ) ) IMPORTING number = DATA(lv_latest_num) returncode = DATA(lv_code) returned_quantity = DATA(lv_qty) ). CATCH cx_nr_object_not_found. CATCH cx_number_ranges INTO DATA(lo_error). LOOP AT lt_entities INTO DATA(ls_entities). APPEND VALUE #( %cid = ls_entities-%cid %key = ls_entities-%key ) TO failed-zi_travel_detail. APPEND VALUE #( %cid = ls_entities-%cid %key = ls_entities-%key %msg = lo_error ) TO reported-zi_travel_detail. ENDLOOP. EXIT. ENDTRY.. ASSERT lv_qty = lines( lt_entities ). DATA(lv_curr_num) = lv_latest_num - lv_qty. LOOP AT lt_entities INTO ls_entities. lv_curr_num = lv_curr_num + 1. APPEND VALUE #( %cid = ls_entities-%cid TravelId = lv_curr_num ) TO mapped-zi_travel_detail. ENDLOOP. ENDMETHOD. METHOD earlynumbering_cba_Booking. DATA : lv_max_booking TYPE /dmo/booking_id. READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail BY \_booking FROM CORRESPONDING #( entities ) LINK DATA(lt_link_data). LOOP AT entities ASSIGNING FIELD-SYMBOL(&lt;ls_group_entity&gt;) GROUP BY &lt;ls_group_entity&gt;-TravelId. lv_max_booking = REDUCE #( INIT lv_max = CONV /dmo/booking_id( '0' ) FOR ls_link IN lt_link_data USING KEY entity WHERE ( source-TravelId = &lt;ls_group_entity&gt;-TravelId ) NEXT lv_max = COND /dmo/booking_id( WHEN lv_max &lt; ls_link-target-BookingId THEN ls_link-target-BookingId ELSE lv_max ) ). lv_max_booking = REDUCE #( INIT lv_max = lv_max_booking FOR ls_entity IN entities USING KEY entity WHERE ( TravelId = &lt;ls_group_entity&gt;-TravelId ) FOR ls_booking IN ls_entity-%target NEXT lv_max = COND /dmo/booking_id( WHEN lv_max &lt; ls_booking-BookingId THEN ls_booking-BookingId ELSE lv_max ) ). LOOP AT entities ASSIGNING FIELD-SYMBOL(&lt;ls_entities&gt;) USING KEY entity WHERE TravelId = &lt;ls_group_entity&gt;-TravelId. LOOP AT &lt;ls_entities&gt;-%target ASSIGNING FIELD-SYMBOL(&lt;ls_booking&gt;). IF &lt;ls_booking&gt;-BookingId IS INITIAL. lv_max_booking += 10. APPEND CORRESPONDING #( &lt;ls_booking&gt; ) TO mapped-zi_booking_detail ASSIGNING FIELD-SYMBOL(&lt;ls_new_map_book&gt;). &lt;ls_new_map_book&gt;-BookingId = lv_max_booking. ENDIF. ENDLOOP. ENDLOOP. ENDLOOP. ENDMETHOD. METHOD AcceptTravel. MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky OverallStatus = 'A') ). READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_result). result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky %param = ls_result ) ). ENDMETHOD. METHOD CopyTravel. ENDMETHOD. METHOD RecalcTotalPrice. TYPES : BEGIN OF ty_total, price TYPE /dmo/total_price, curr TYPE /dmo/currency_code, END OF ty_total. DATA : lt_total TYPE TABLE OF ty_total, lv_conv_price TYPE ty_total-price. READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail FIELDS ( BookingFee CurrencyCode ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel). DELETE lt_travel WHERE CurrencyCode IS INITIAL. READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail BY \_booking FIELDS ( FlightPrice CurrencyCode ) WITH CORRESPONDING #( lt_travel ) RESULT DATA(lt_ba_booking) . READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_booking_detail BY \_bookingsuppl FIELDS ( Price CurrencyCode ) WITH CORRESPONDING #( lt_ba_booking ) RESULT DATA(lt_ba_bookingsupp) . LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(&lt;ls_travel&gt;). lt_total = VALUE #( ( price = &lt;ls_travel&gt;-BookingFee curr = &lt;ls_travel&gt;-CurrencyCode ) ). LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(&lt;ls_booking&gt;) USING KEY entity WHERE TravelId = &lt;ls_travel&gt;-TravelId AND CurrencyCode IS NOT INITIAL. APPEND VALUE #( price = &lt;ls_booking&gt;-FlightPrice curr = &lt;ls_booking&gt;-CurrencyCode ) TO lt_total. LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(&lt;ls_bookingsupp&gt;) USING KEY entity WHERE TravelId = &lt;ls_booking&gt;-TravelId AND BookingId = &lt;ls_booking&gt;-BookingId AND CurrencyCode IS NOT INITIAL. APPEND VALUE #( price = &lt;ls_bookingsupp&gt;-Price curr = &lt;ls_bookingsupp&gt;-CurrencyCode ) TO lt_total. ENDLOOP. ENDLOOP. LOOP AT lt_total ASSIGNING FIELD-SYMBOL(&lt;ls_total&gt;). IF &lt;ls_total&gt;-curr = &lt;ls_travel&gt;-CurrencyCode . lv_conv_price = &lt;ls_total&gt;-price . ELSE. /dmo/cl_flight_amdp=&gt;convert_currency( EXPORTING iv_amount = &lt;ls_total&gt;-price iv_currency_code_source = &lt;ls_total&gt;-curr iv_currency_code_target = &lt;ls_travel&gt;-CurrencyCode iv_exchange_rate_date = cl_abap_context_info=&gt;get_system_date( ) IMPORTING ev_amount = lv_conv_price ). ENDIF. &lt;ls_travel&gt;-TotalPrice = &lt;ls_travel&gt;-TotalPrice + lv_conv_price. ENDLOOP. MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail UPDATE FIELDS ( TotalPrice ) WITH CORRESPONDING #( lt_travel ). ENDLOOP. ENDMETHOD. METHOD RejectTravel. MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky OverallStatus = 'X') ) REPORTED DATA(lt_travel). READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_result). result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky %param = ls_result ) ). ENDMETHOD. METHOD CalcTotalPrice. MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail EXECUTE RecalcTotalPrice FROM CORRESPONDING #( keys ). ENDMETHOD. ENDCLASS. </code></pre><P>18.&nbsp;<SPAN>Here we are calculating the total&nbsp; price , whenever somebody changes the total</SPAN><SPAN>&nbsp;&nbsp;</SPAN><SPAN>Price and currency manually this determination&nbsp; should call on transactional phase(on modify)</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>METHOD CalcTotalPrice. MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail EXECUTE RecalcTotalPrice FROM CORRESPONDING #( keys ). ENDMETHOD. </code></pre><P>19.&nbsp;&nbsp;<SPAN>will call RecacTotalPrice for each determination</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>All the travel id which we modify&nbsp; will trigger when we are calculating total price</SPAN><SPAN>&nbsp;&nbsp;</SPAN></P><P><SPAN>RecacTotalPrice--&gt; will be called . We need to write the logic to modify</SPAN><SPAN>&nbsp;</SPAN><SPAN>Our BO instance based on travel ID And it will read and updae the price&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>&nbsp;</SPAN><SPAN>Here the action will take care of the process – when we change the price&nbsp;</SPAN><SPAN>&nbsp;</SPAN><SPAN>( based on determination ) action will be called&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>And as soon as price filed changes, determination happens</SPAN><SPAN>&nbsp;&nbsp;</SPAN><SPAN>And we need to read the travel entity with fields booking fee and currency code</SPAN><SPAN>&nbsp;&nbsp;</SPAN><SPAN>And we need to provide travel IDs which is present in keys&nbsp;</SPAN><SPAN>&nbsp;</SPAN><SPAN>Result is taken in LT_TRAVEL</SPAN><SPAN>&nbsp;</SPAN></P><P><SPAN>Same thing we need to do it for boking and booking suppliment</SPAN><SPAN>&nbsp;</SPAN></P><pre class="lia-code-sample language-abap"><code>METHOD RecalcTotalPrice. TYPES : BEGIN OF ty_total, price TYPE /dmo/total_price, curr TYPE /dmo/currency_code, END OF ty_total. DATA : lt_total TYPE TABLE OF ty_total, lv_conv_price TYPE ty_total-price. READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail FIELDS ( BookingFee CurrencyCode ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel). DELETE lt_travel WHERE CurrencyCode IS INITIAL. READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail BY \_booking FIELDS ( FlightPrice CurrencyCode ) WITH CORRESPONDING #( lt_travel ) RESULT DATA(lt_ba_booking) . READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_booking_detail BY \_bookingsuppl FIELDS ( Price CurrencyCode ) WITH CORRESPONDING #( lt_ba_booking ) RESULT DATA(lt_ba_bookingsupp) . LOOP AT lt_travel ASSIGNING FIELD-SYMBOL(&lt;ls_travel&gt;). lt_total = VALUE #( ( price = &lt;ls_travel&gt;-BookingFee curr = &lt;ls_travel&gt;-CurrencyCode ) ). LOOP AT lt_ba_booking ASSIGNING FIELD-SYMBOL(&lt;ls_booking&gt;) USING KEY entity WHERE TravelId = &lt;ls_travel&gt;-TravelId AND CurrencyCode IS NOT INITIAL. APPEND VALUE #( price = &lt;ls_booking&gt;-FlightPrice curr = &lt;ls_booking&gt;-CurrencyCode ) TO lt_total. LOOP AT lt_ba_bookingsupp ASSIGNING FIELD-SYMBOL(&lt;ls_bookingsupp&gt;) USING KEY entity WHERE TravelId = &lt;ls_booking&gt;-TravelId AND BookingId = &lt;ls_booking&gt;-BookingId AND CurrencyCode IS NOT INITIAL. APPEND VALUE #( price = &lt;ls_bookingsupp&gt;-Price curr = &lt;ls_bookingsupp&gt;-CurrencyCode ) TO lt_total. ENDLOOP. ENDLOOP. LOOP AT lt_total ASSIGNING FIELD-SYMBOL(&lt;ls_total&gt;). IF &lt;ls_total&gt;-curr = &lt;ls_travel&gt;-CurrencyCode . lv_conv_price = &lt;ls_total&gt;-price . ELSE. /dmo/cl_flight_amdp=&gt;convert_currency( EXPORTING iv_amount = &lt;ls_total&gt;-price iv_currency_code_source = &lt;ls_total&gt;-curr iv_currency_code_target = &lt;ls_travel&gt;-CurrencyCode iv_exchange_rate_date = cl_abap_context_info=&gt;get_system_date( ) IMPORTING ev_amount = lv_conv_price ). ENDIF. &lt;ls_travel&gt;-TotalPrice = &lt;ls_travel&gt;-TotalPrice + lv_conv_price. ENDLOOP. MODIFY ENTITIES OF zi_travel_detail in LOCAL MODE ENTITY zi_travel_detail UPDATE FIELDS ( TotalPrice ) WITH CORRESPONDING #( lt_travel ). ENDLOOP. ENDMETHOD. </code></pre><P>20.&nbsp;&nbsp;<SPAN class="">Class for booking</SPAN><SPAN class="">&nbsp; suppliment</SPAN></P><pre class="lia-code-sample language-abap"><code>CLASS lhc_zi_booking_supp DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS CalcTotalPrice FOR DETERMINE ON MODIFY IMPORTING keys FOR zi_booking_supp~CalcTotalPrice. METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION IMPORTING REQUEST requested_authorizations FOR zi_booking_supp RESULT result. ENDCLASS. CLASS lhc_zi_booking_supp IMPLEMENTATION. METHOD CalcTotalPrice. ENDMETHOD. METHOD get_global_authorizations. ENDMETHOD. ENDCLASS. CLASS lhc_zi_booking_detail DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS earlynumbering_cba_Bookingsupp FOR NUMBERING IMPORTING entities FOR CREATE zi_booking_detail\_Bookingsuppl. METHODS CalcTotalPrice FOR DETERMINE ON MODIFY IMPORTING keys FOR zi_booking_detail~CalcTotalPrice. METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION IMPORTING REQUEST requested_authorizations FOR zi_booking_detail RESULT result. ENDCLASS. CLASS lhc_zi_booking_detail IMPLEMENTATION. METHOD earlynumbering_cba_Bookingsupp. DATA: max_booking_suppl_id TYPE /dmo/booking_supplement_id . READ ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_booking_detail BY \_Bookingsuppl FROM CORRESPONDING #( entities ) LINK DATA(booking_supplements). " Loop over all unique tky (TravelID + BookingID) LOOP AT entities ASSIGNING FIELD-SYMBOL(&lt;booking_group&gt;) GROUP BY &lt;booking_group&gt;-%tky. " Get highest bookingsupplement_id from bookings belonging to booking max_booking_suppl_id = REDUCE #( INIT max = CONV /dmo/booking_supplement_id( '0' ) FOR booksuppl IN booking_supplements USING KEY entity WHERE ( source-TravelId = &lt;booking_group&gt;-TravelId AND source-BookingId = &lt;booking_group&gt;-BookingId ) NEXT max = COND /dmo/booking_supplement_id( WHEN booksuppl-target-BookingSupplementId &gt; max THEN booksuppl-target-BookingSupplementId ELSE max ) ). " Get highest assigned bookingsupplement_id from incoming entities max_booking_suppl_id = REDUCE #( INIT max = max_booking_suppl_id FOR entity IN entities USING KEY entity WHERE ( TravelId = &lt;booking_group&gt;-TravelId AND BookingId = &lt;booking_group&gt;-BookingId ) FOR target IN entity-%target NEXT max = COND /dmo/booking_supplement_id( WHEN target-BookingSupplementId &gt; max THEN target-BookingSupplementId ELSE max ) ). " Loop over all entries in entities with the same TravelID and BookingID LOOP AT entities ASSIGNING FIELD-SYMBOL(&lt;booking&gt;) USING KEY entity WHERE TravelId = &lt;booking_group&gt;-TravelId AND BookingId = &lt;booking_group&gt;-BookingId. " Assign new booking_supplement-ids LOOP AT &lt;booking&gt;-%target ASSIGNING FIELD-SYMBOL(&lt;booksuppl_wo_numbers&gt;). APPEND CORRESPONDING #( &lt;booksuppl_wo_numbers&gt; ) TO mapped-zi_booking_supp ASSIGNING FIELD-SYMBOL(&lt;mapped_booksuppl&gt;). IF &lt;booksuppl_wo_numbers&gt;-BookingSupplementId IS INITIAL. max_booking_suppl_id += 1 . &lt;mapped_booksuppl&gt;-BookingSupplementId = max_booking_suppl_id . ENDIF. ENDLOOP. ENDLOOP. ENDLOOP. ENDMETHOD. </code></pre><P>21.&nbsp;<SPAN>Based on the booking fee&nbsp; we need to calculate the total price&nbsp;</SPAN><SPAN>&nbsp;,&nbsp;</SPAN><SPAN>So we need to write the logic in calcTotal price</SPAN><SPAN>&nbsp;method</SPAN></P><pre class="lia-code-sample language-abap"><code>METHOD CalcTotalPrice. DATA : it_travel TYPE STANDARD TABLE OF zpd_dt_travel WITH UNIQUE HASHED KEY key COMPONENTS travel_id. it_travel = CORRESPONDING #( keys DISCARDING DUPLICATES MAPPING travel_id = TravelId ). MODIFY ENTITIES OF zi_travel_detail IN LOCAL MODE ENTITY zi_travel_detail EXECUTE RecalcTotalPrice FROM CORRESPONDING #( it_travel ). ENDMETHOD. </code></pre><P>22. OUTPUT</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_1-1751356413745.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281056i9F607E3B71E7BBD6/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_1-1751356413745.png" alt="Pradeep555_1-1751356413745.png" /></span></P><P>&nbsp;</P><P><SPAN>23.&nbsp;<SPAN class=""><SPAN class="">Edit--&gt; changing booking fee from 140 USD to 240</SPAN></SPAN><SPAN class="">&nbsp;USD</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_3-1751356464751.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281061i80F49161DD120248/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_3-1751356464751.png" alt="Pradeep555_3-1751356464751.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_4-1751356486334.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281062iBFFF53176F80B0A8/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_4-1751356486334.png" alt="Pradeep555_4-1751356486334.png" /></span></P><P>24.&nbsp; &nbsp;<SPAN>Click on save</SPAN><SPAN>&nbsp;</SPAN><SPAN>&lt;&lt; after saving , the total price is still the same ---&gt; not updated at the screen level</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_5-1751356553915.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281066iE1EEC86B86A98E04/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_5-1751356553915.png" alt="Pradeep555_5-1751356553915.png" /></span></P><P>25.&nbsp;&nbsp;<SPAN class=""><SPAN class="">When we refresh the page—the total price gets updated</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_6-1751356589520.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281067iB2E6360B32F2DBFB/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_6-1751356589520.png" alt="Pradeep555_6-1751356589520.png" /></span></P><P>&nbsp;</P><P>26.&nbsp; N<SPAN>ow we need to use the side effects to make the data refreshed on save at screen level</SPAN><SPAN>&nbsp;, So n</SPAN><SPAN>ow it should not only be updated in the transactional buffer – it should&nbsp; also be updated in the front end&nbsp;</SPAN><SPAN>&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_7-1751356689309.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281068iF69F21F2160CCEBB/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_7-1751356689309.png" alt="Pradeep555_7-1751356689309.png" /></span></P><P>27.&nbsp;&nbsp;<SPAN class=""><SPAN class="">Change the booking fee 258 USD&nbsp; and click on save</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_8-1751356741975.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281069i705DAB1959677231/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_8-1751356741975.png" alt="Pradeep555_8-1751356741975.png" /></span></P><P>28.&nbsp;<SPAN class=""><SPAN class="">As soon as you click on save</SPAN></SPAN><SPAN class="">&nbsp;</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Pradeep555_9-1751356776648.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281070i48252591EEDCAC73/image-size/large?v=v2&amp;px=999" role="button" title="Pradeep555_9-1751356776648.png" alt="Pradeep555_9-1751356776648.png" /></span></P><P>&nbsp;</P><P>Thanks and regards&nbsp;</P><P>-PRADEEP ISHWAR DEVADIGA</P><P><SPAN>&nbsp;</SPAN></P> 2025-07-02T10:28:03.987000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/you-won-t-believe-where-zllm-s-documentation-lives-and-how-it-got-there/ba-p/14142558 You Won't Believe Where ZLLM's Documentation Lives (And How It Got There) 2025-07-02T12:45:53.530000+02:00 Alice_V https://community.sap.com/t5/user/viewprofilepage/user-id/609259 <P class=""><STRONG>How I Made AI Write Its Own Documentation... In SAP's Standard Format</STRONG></P><P class=""><EM>Spoiler: The AI is already documenting itself in production*.</EM></P><P class=""><EM><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChatGPT Image Jul 2, 2025, 12_07_15 PM.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281751i486F7C73DE5E4FF9/image-size/large?v=v2&amp;px=999" role="button" title="ChatGPT Image Jul 2, 2025, 12_07_15 PM.png" alt="ChatGPT Image Jul 2, 2025, 12_07_15 PM.png" /></span></EM></P><HR /><P class="">Hello again! <span class="lia-unicode-emoji" title=":waving_hand:">👋</span> It's Alice, and I have a confession: I absolutely <STRONG>love</STRONG> writing documentation.</P><P class="">But I hate writing it <STRONG>BY HAND</STRONG>. Especially in SAP's bizarre ITF format - that cryptic markup language designed back when the closest thing to modern markup was SGML, and HTML didn't even exist yet!</P><P class=""><EM>(Fun fact: ITF format was actually designed for SAPscript in the early 1980s as part of SAP R/2 - when "markup language" meant something completely different! </EM><STRONG>^_^</STRONG><EM>)</EM></P><P class="">But here's the thing - ZLLM has <STRONG>incredible</STRONG> documentation. Comprehensive, detailed, and perfectly formatted. And it lives exactly where every SAP developer <STRONG>NOT</STRONG> expects it: behind the standard <STRONG>"Show Documentation"</STRONG> button <span class="lia-unicode-emoji" title=":grinning_face_with_big_eyes:">😃</span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Alice_V_0-1751454104363.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281748i6712CECE39FC9FA7/image-size/medium?v=v2&amp;px=400" role="button" title="Alice_V_0-1751454104363.png" alt="Alice_V_0-1751454104363.png" /></span></P><P>&nbsp;</P><H3 id="ember4460" id="toc-hId-1863196651">Plot Twist:</H3><P class="">I didn't write a single line of that documentation manually.</P><P class=""><STRONG>ZLLM documented itself.</STRONG></P><HR /><H3 id="ember4463" id="toc-hId-1666683146">The Documentation That Writes Itself</H3><P class="">Click on any ZLLM class in SE80 or ADT. Hit <STRONG>CTRL+SHIFT+F2</STRONG> (Show Documentation).</P><P class="">What you'll see isn't your typical sparse ABAP documentation. It's rich, detailed, with examples, architecture diagrams, and usage patterns. All perfectly formatted in SAP's native documentation system.</P><P class=""><STRONG>Here's what makes this magical:</STRONG></P><P class="">The documentation exists in <STRONG>standard SAP format</STRONG> (ITF), appears in <STRONG>standard SAP locations</STRONG>, but was generated by <STRONG>modern AI</STRONG> and written in <STRONG>human-readable Markdown</STRONG> first.</P><HR /><H2 id="ember4468" id="toc-hId-1341086922">How I Built The Documentation Factory</H2><H3 id="ember4469" id="toc-hId-1273656136">Step 1: The Analysis Phase</H3><PRE>" ZLLM analyzes the codebase DATA(lo_analyzer) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Analyze this ABAP class and extract:' '- Purpose and responsibility' '- Public methods and parameters' '- Usage patterns and examples' '- Integration points: {T}' io_llm = lo_llm ).</PRE><H3 id="ember4470" id="toc-hId-1077142631">Step 2: The Generation Phase</H3><PRE>" Generate comprehensive Markdown documentation DATA(lo_generator) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Create technical documentation in Markdown format:' '- Overview section with clear purpose' '- Method documentation with examples' '- Code samples showing real usage' '- Integration notes and best practices' 'Based on analysis: {T}' io_llm = lo_llm ).</PRE><H3 id="ember4471" id="toc-hId-880629126">Step 3: The Integration Magic</H3><PRE>" Chain it all together DATA(lo_doc_flow) = zcl_llm_00_flow_lazy=&gt;new( VALUE #( ( lo_analyzer ) ( lo_generator ) ) ). " Generate docs for entire framework DATA(lr_result) = lo_doc_flow-&gt;exec( REF #( class_metadata ) ).</PRE><P class=""><EM>For the Markdown → ITF conversion and integration with SAP's documentation system, I used another one of my frameworks: </EM><STRONG><EM>XRAY</EM></STRONG><EM>. But that's a story for another article... </EM><STRONG>^_^</STRONG></P><HR /><H3 id="ember4473" id="toc-hId-684115621">The Real Magic: Production-Ready Documentation</H3><P class="">This isn't a toy example. This is <STRONG>live, production documentation</STRONG> that:</P><P class=""><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>Appears in standard SAP tools</STRONG> (SE80, ADT, SE11)</P><P class=""><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>Follows SAP documentation conventions</STRONG></P><P class=""><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>Updates automatically</STRONG>when code changes</P><P class=""><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>Includes real examples</STRONG>and usage patterns</P><P class=""><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span><STRONG>Maintains technical accuracy</STRONG> through AI analysis</P><H3 id="ember4480" id="toc-hId-487602116">### Before vs After:</H3><P class=""><STRONG>Traditional SAP Documentation:</STRONG></P><PRE>* It is a class.</PRE><P class=""><STRONG>ZLLM-Generated Documentation:</STRONG></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Alice_V_1-1751452613795.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281732i7CDDAF2B7649AF1E/image-size/medium?v=v2&amp;px=400" role="button" title="Alice_V_1-1751452613795.png" alt="Alice_V_1-1751452613795.png" /></span></P><DIV class=""><DIV class=""><DIV class=""><P>&nbsp;</P></DIV></DIV></DIV><HR /><H2 id="ember4485" id="toc-hId-162005892">Why This Changes a Lot</H2><H3 id="ember4486" id="toc-hId-94575106">For SAP Developers:</H3><UL><LI>No more "TODO: Add documentation" comments</LI><LI>Comprehensive docs appear automatically in familiar places</LI><LI>Examples and usage patterns generated from actual code</LI></UL><P class=""><STRONG>For Enterprise Teams:</STRONG></P><UL><LI>Documentation stays current with code changes</LI><LI>Consistent format across entire codebase</LI><LI>Onboarding new developers becomes trivial</LI></UL><P class=""><STRONG>For AI Adoption:</STRONG></P><UL><LI>Demonstrates practical AI value in daily development</LI><LI>Shows integration with existing enterprise tools</LI><LI>Proves AI can enhance rather than replace existing workflows</LI></UL><HR /><H3 id="ember4492" id="toc-hId--177169768">The Recursive Beauty</H3><P class="">Here's the beautiful irony: <STRONG>ZLLM used itself to document itself.</STRONG></P><P class="">The framework that makes enterprise AI integration effortless also made documenting itself effortless. It's AI all the way down.</P><HR /><H3 id="ember4495" id="toc-hId--373683273">How You Can Build This</H3><P class="">Want to auto-document your own ABAP code? Here's the starter pattern:</P><PRE>METHOD auto_document_class. " 1. Extract class metadata DATA(lo_metadata) = extract_class_info( iv_class_name ). " 2. Generate documentation DATA(lo_doc_step) = zcl_llm_00_step_lazy=&gt;new_from_string( iv_usr = 'Create comprehensive documentation for this ABAP class: {T}' io_llm = lo_llm ). " 3. Chain and execute DATA(lo_flow) = zcl_llm_00_flow_lazy=&gt;new( VALUE #( ( lo_doc_step ) ) ). DATA(lv_markdown_doc) = lo_flow-&gt;start( REF #( lo_metadata ) )-&gt;to_string( ). ENDMETHOD.</PRE><HR /><H2 id="ember4497" id="toc-hId--276793771">The Bigger Picture</H2><P class="">This isn't just about documentation. It's about <STRONG>AI that enhances existing enterprise workflows</STRONG> instead of disrupting them.</P><P class=""><STRONG>Traditional AI Integration:</STRONG> "We need new tools, new processes, new training..."</P><P class=""><STRONG>ZLLM Approach:</STRONG> "Your existing tools just got smarter."</P><P class="">The documentation appears exactly where SAP developers (not?) expect it. No new interfaces to learn. No new processes to adopt. Just better, more comprehensive information in familiar places.</P><HR /><H2 id="ember4503" id="toc-hId--473307276">What's Next?</H2><P class="">This is just one example of ZLLM eating its own dog food. Other production uses:</P><P class=""><STRONG>Code Analysis</STRONG>- Analyzing patterns across the entire ABAP stack</P><P class=""><STRONG>Performance Monitoring</STRONG>- Generating insights from system metrics</P><P class=""><STRONG>Test Generation</STRONG>- Creating unit tests from business requirements</P><P class=""><STRONG>Migration Planning</STRONG> - Analyzing code dependencies for S/4HANA migration</P><HR /><H3 id="ember4509" id="toc-hId--963223788">Ready to Document Your Code Automatically?</H3><P class=""><span class="lia-unicode-emoji" title=":star:">⭐</span><STRONG>Explore ZLLM: -&gt; github/oisee/zllm</STRONG></P><P class=""><STRONG>Comment below:</STRONG>What part of your ABAP development would you want AI to handle?</P><P class=""><span class="lia-unicode-emoji" title=":counterclockwise_arrows_button:">🔄</span><STRONG>Share</STRONG> if you think your SAP team needs this</P><P class=""><STRONG>Try it yourself:</STRONG></P><P class="">1. Install ZLLM in your development system</P><P class="">2. Run the documentation generator on your classes</P><P class="">3. Watch as comprehensive docs appear in standard SAP locations</P><P class="">4. Never write manual documentation again</P><HR /><P class=""><STRONG>About Alice Vinogradova:</STRONG></P><P class="">Senior Software Engineer with 20+ years in ABAP/SAP. I specialize in making enterprise AI practical, starting with solving our own problems first. If the AI can't document itself, how can it document your business processes?</P><P class=""><STRONG>P.S.</STRONG> Yes, this article was edited by ZLLM too. And the Markdown → ITF conversion? That's handled by my <STRONG>XRAY</STRONG> framework - another story of making SAP development less painful. It's recursive intelligence all the way down.</P><HR /><P class=""><STRONG>*production </STRONG>for development - is development.</P><P class=""><STRONG>Tags:</STRONG> #SAP #ABAP #AI #Documentation #TechLeadership #Automation</P><P class=""><EM>"The ideal documentation is one that doesn't need to be written because it writes itself."</EM></P> 2025-07-02T12:45:53.530000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/abap-cloud-number-ranges-using-snro/ba-p/14142454 ABAP Cloud - Number ranges ( Using SNRO ) 2025-07-02T13:44:45.577000+02:00 sanjay22 https://community.sap.com/t5/user/viewprofilepage/user-id/1535416 <P><STRONG><SPAN>ABAP Cloud - Number ranges<SPAN>&nbsp;</SPAN></SPAN></STRONG></P><P><SPAN>How can you use number ranges in ABAP Cloud and does this actually still make sense? In this article we will look at some of the background information.<SPAN>&nbsp;&nbsp;</SPAN></SPAN></P><P><SPAN>Number range objects and number ranges have long been a standard feature across various SAP specialist modules. But what’s the current approach in ABAP Cloud? Do we still need these objects? In this article, we’ll explore the new concepts introduced in ABAP Cloud and how you can effectively work with them.<SPAN>&nbsp;</SPAN></SPAN></P><P><STRONG><SPAN>Introduction</SPAN></STRONG></P><P><SPAN>In traditional on-premise systems, the SNRO transaction was your go-to tool for creating and managing number ranges. However, with ABAP Cloud, the landscape has changed transactions like SNRO are no longer available, and maintaining intervals directly is no longer an option. Instead, SAP now offers a set of <STRONG><SPAN>ABAP APIs<SPAN> along with a<STRONG><SPAN> dedicated Fiori app<SPAN> to handle number range management. In this post, we’ll take a closer look at these new tools and how you can use them effectively in the cloud environment.</SPAN></SPAN></STRONG></SPAN></SPAN></STRONG></SPAN></P><P><SPAN>Why do we actually need number ranges and consecutive numbers in the system? Data is stored in databases and records in relational databases usually require a unique key. To assign numbers automatically, we could always look at the database and calculate the current ID plus 1 to get a new unique key. However, since we are not alone on the system and several booking processes can run at the same time, this would not guarantee that we would always receive a unique number. Number range objects therefore manage the individual number range statuses and always give us a unique number via a function and take care of the increase.</SPAN></P><P><STRONG><SPAN>ABAP Cloud</SPAN></STRONG></P><P><SPAN>When developing with ABAP Cloud, we rely on the ABAP RESTful Programming Model, or RAP for short, which very often uses GUIDs to manage the keys. The GUIDs are generated randomly and we don't have to worry about managing the key. Furthermore, we can change any field in the data record in the workflow if we want to. If we need a readable or unique key in our data record, we can also use a semantic key, which we can also declare as unique, but we have to carry out the check ourselves.</SPAN></P><P><SPAN>However, with this method we cannot prove any sequence or gaps in the data. Therefore, in certain technical scenarios it still makes sense to use number ranges to create a semantic key.</SPAN></P><P><STRONG><SPAN>Creation<SPAN>&nbsp;</SPAN></SPAN></STRONG></P><P><SPAN>You can easily create the number range object using the ABAP Development Tools. In the following steps we create a domain and then the appropriate object.</SPAN></P><P><STRONG><SPAN>Domain</SPAN></STRONG></P><P><SPAN>In order to create a number range, we first need a domain that determines the data type. To do this, we create a domain using the context menu; a new domain on our system.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1751447849631.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281697i14125F098676E677/image-size/medium?v=v2&amp;px=400" role="button" title="sanjay22_0-1751447849631.png" alt="sanjay22_0-1751447849631.png" /></span></P><P><SPAN class=""><SPAN class="">We then give the domain a type that <SPAN class="">determines<SPAN class=""> the number and options of the generated numbers.</SPAN></SPAN></SPAN></SPAN></P><P><STRONG><SPAN>Number Range Object (ADT)</SPAN></STRONG></P><P><SPAN>We can now create a number range object. Here we have to make sure that the name is not too long, as the field currently only has 10 characters.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_2-1751447688733.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281696i13E2231896BE3102/image-size/large?v=v2&amp;px=999" role="button" title="sanjay22_2-1751447688733.png" alt="sanjay22_2-1751447688733.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-left" image-alt="sanjay22_1-1751447649935.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281695iB0D437613087A38C/image-size/large?v=v2&amp;px=999" role="button" title="sanjay22_1-1751447649935.png" alt="sanjay22_1-1751447649935.png" /></span></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><SPAN class=""><SPAN class="">Created the </SPAN><SPAN class="">ABAP class in </SPAN><SPAN class="">RAP application using ADT </SPAN><SPAN class="">to check SNRO number range object</SPAN><SPAN class="">.</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>CLASS zcl_rap_snro_number_range DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_rap_snro_number_range IMPLEMENTATION. METHOD if_oo_adt_classrun~main. TRY. zcl_sm_helper_class=&gt;get_snro_id( EXPORTING iv_range_nr = '01' iv_object = 'ZSM_USERID' IMPORTING ev_num = DATA(lv_num) ). CATCH cx_number_ranges INTO DATA(lx_obj). out-&gt;write( lx_obj-&gt;get_text( ) ). ENDTRY. out-&gt;write( |EI{ lv_num+12(8) }| ). ENDMETHOD. ENDCLASS. </code></pre><P><SPAN class=""><SPAN class="">Next</SPAN><SPAN class=""> we have </SPAN><SPAN class="">an</SPAN><SPAN class=""> helper class --&gt;&gt; </SPAN></SPAN><SPAN class=""><SPAN class=""><STRONG>ZCL_SM_HELPER_CLASS</STRONG>.</SPAN></SPAN></P><pre class="lia-code-sample language-abap"><code>CLASS zcl_sm_helper_class DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. CLASS-METHODS get_snro_id IMPORTING iv_range_nr TYPE zsm_NRNR iv_object TYPE zsm_NROBJ EXPORTING ev_num TYPE zsm_num RAISING cx_number_ranges. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_sm_helper_class IMPLEMENTATION. METHOD get_snro_id. TRY. cl_numberrange_intervals=&gt;read( EXPORTING nr_range_nr1 = iv_range_nr * nr_range_nr2 = object = iv_object * subobject = IMPORTING interval = DATA(ls_interval) ). CATCH cx_nr_object_not_found INTO DATA(lx_obj1). " TODO: variable is assigned but never used (ABAP cleaner) CATCH cx_nr_subobject INTO DATA(lx_obj2). " TODO: variable is assigned but never used (ABAP cleaner) CATCH cx_number_ranges INTO DATA(lx_obj3). " TODO: variable is assigned but never used (ABAP cleaner) ENDTRY. IF ls_interval IS INITIAL. TRY. cl_numberrange_intervals=&gt;create( interval = VALUE #( ( nrrangenr = '01' fromnumber = '00000001' tonumber = '99999999' ) ) object = iv_object ). * subobject = * option = * IMPORTING * error = * error_inf = * error_iv = * warning = CATCH cx_nr_object_not_found INTO DATA(lx_obj4). " TODO: variable is assigned but never used (ABAP cleaner) CATCH cx_number_ranges INTO DATA(lx_obj5). " TODO: variable is assigned but never used (ABAP cleaner) ENDTRY. ENDIF. TRY. cl_numberrange_runtime=&gt;number_get( EXPORTING * ignore_buffer = nr_range_nr = iv_range_nr object = iv_object * quantity = * subobject = * toyear = IMPORTING number = ev_num * returncode = * returned_quantity = ). CATCH cx_number_ranges INTO DATA(lx_obj). RAISE EXCEPTION lx_obj. ENDTRY. ENDMETHOD. ENDCLASS. </code></pre><P><SPAN class=""><SPAN class="">OUTPUT: We are getting serial numbers from SNRO in the expected format.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1751448334269.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281704iEE1BEBD964AEE0BF/image-size/large?v=v2&amp;px=999" role="button" title="sanjay22_0-1751448334269.png" alt="sanjay22_0-1751448334269.png" /></span></P> 2025-07-02T13:44:45.577000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/bdc-batch-data-communication-using-session-method-and-call-transaction/ba-p/14141453 BDC Batch Data Communication using Session Method And Call Transaction Method 2025-07-02T14:14:43.654000+02:00 manijangiti https://community.sap.com/t5/user/viewprofilepage/user-id/2174619 <P>This Blog provides an overview of BDC (Batch Data Communication) using the Session Method. BDC is a classic data migration technique in SAP. The Session Method is suitable for large volumes of data and allows better error handling<BR /><BR />For Recording the Transaction T code: <STRONG>SHDB<BR /></STRONG>Batch Input Sessions<STRONG>:&nbsp; SM35</STRONG><BR /><STRONG>1.Session Method</STRONG></P><pre class="lia-code-sample language-abap"><code>REPORT ZBDC_SESSIONMETHOD_MA. "Type declaration for customer structure TYPES: BEGIN OF ty_customer, kunnr TYPE kunnr, " Customer Number name1 TYPE name1_gp, " Name ort01 TYPE ort01, " City END OF ty_customer. "Internal tables and variables DATA: it_customer TYPE TABLE OF ty_customer, " Internal table to hold customer data wa_customer TYPE ty_customer, " Work area it_bdcdata TYPE TABLE OF bdcdata, " BDC table wa_bdcdata TYPE bdcdata, " BDC work area v_file TYPE string. " File path variable DATA: p_pp TYPE string. " Temporary file path variable "BDC session name (used in SM35) DATA: lv_group TYPE apqi-groupid VALUE 'ZCUS_UPLOAD'. "Selection screen to get file path input PARAMETERS: p_file TYPE rlgrap-filename OBLIGATORY. "AT SELECTION SCREEN: F4 help to choose file AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file. CALL FUNCTION 'F4_FILENAME' IMPORTING file_name = p_file. "START OF SELECTION START-OF-SELECTION. "Move user-selected file to internal variable p_pp = p_file. "Upload flat file with customer data CALL FUNCTION 'GUI_UPLOAD' EXPORTING filename = p_pp filetype = 'ASC' has_field_separator = '|' " Pipe delimiter TABLES data_tab = it_customer. "Check if file has data IF it_customer IS INITIAL. WRITE: / 'No data found in file.'. EXIT. ENDIF. "Open BDC session CALL FUNCTION 'BDC_OPEN_GROUP' EXPORTING client = sy-mandt group = lv_group user = sy-uname keep = 'X' " Keep session after execution holddate = sy-datum. " Process date "Loop through uploaded customer data LOOP AT it_customer INTO wa_customer. CLEAR it_bdcdata. "First screen entries PERFORM bdc_dynpro USING 'ZBDC_SCREEN' '1000'. PERFORM bdc_field USING 'BDC_CURSOR' 'P_ORT01'. PERFORM bdc_field USING 'BDC_OKCODE' '=ONLI'. PERFORM bdc_field USING 'P_KUNNR' wa_customer-kunnr. PERFORM bdc_field USING 'P_NAME' wa_customer-name1. PERFORM bdc_field USING 'P_ORT01' wa_customer-ort01. "Exit screen to return PERFORM bdc_dynpro USING 'ZBDC_SCREEN' '1000'. PERFORM bdc_field USING 'BDC_OKCODE' '/EE'. PERFORM bdc_field USING 'BDC_CURSOR' 'P_KUNNR'. "Insert transaction step into the BDC session CALL FUNCTION 'BDC_INSERT' EXPORTING tcode = 'ZBDC_CUS' TABLES dynprotab = it_bdcdata. ENDLOOP. "Close the BDC session CALL FUNCTION 'BDC_CLOSE_GROUP'. "Success message WRITE: / 'BDC Session created successfully. Use SM35 to process it.'. "----------------------------------------- " Subroutine to add dynpro screen "----------------------------------------- FORM bdc_dynpro USING program screen. CLEAR wa_bdcdata. wa_bdcdata-program = program. wa_bdcdata-dynpro = screen. wa_bdcdata-dynbegin = 'X'. APPEND wa_bdcdata TO it_bdcdata. ENDFORM. "----------------------------------------- " Subroutine to add field values "----------------------------------------- FORM bdc_field USING fnam fval. CLEAR wa_bdcdata. wa_bdcdata-fnam = fnam. wa_bdcdata-fval = fval. APPEND wa_bdcdata TO it_bdcdata. ENDFORM.</code></pre><DIV class="">&nbsp;</DIV><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="manijangiti_1-1751363036602.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281199i79E6CB4545D21325/image-size/medium?v=v2&amp;px=400" role="button" title="manijangiti_1-1751363036602.png" alt="manijangiti_1-1751363036602.png" /></span></P><P>After execute&nbsp; go to Sm35&nbsp;<BR /><BR /><STRONG>2.Call Transaction Method<BR /></STRONG></P><pre class="lia-code-sample language-abap"><code>REPORT ZBDC_CALLTRAN_CUSTOMER. "--- Structure Definition --- TYPES: BEGIN OF ty_customer, kunnr TYPE kunnr, " Customer Number name1 TYPE name1_gp, " Name ort01 TYPE ort01, " City END OF ty_customer. "--- Data Declarations --- DATA: p_file_s TYPE string, " To hold the selected file path it_customer TYPE TABLE OF ty_customer, " Internal table for uploaded data wa_customer TYPE ty_customer, " Work area for one record it_bdcdata TYPE TABLE OF bdcdata, " BDC data table wa_bdcdata TYPE bdcdata. " BDC line "--- File Input Parameter --- PARAMETERS: p_file TYPE IBIPPARMS-PATH OBLIGATORY. "--- F4 Help for File Selection --- AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file. CALL FUNCTION 'F4_FILENAME' IMPORTING file_name = p_file. "--- Main Program Execution --- START-OF-SELECTION. " Assign selected file to variable p_file_s = p_file. " Upload the customer data from text file CALL FUNCTION 'GUI_UPLOAD' EXPORTING filename = p_file_s filetype = 'ASC' has_field_separator = '|' " Data separated by '|' TABLES data_tab = it_customer EXCEPTIONS OTHERS = 1. " Loop over each uploaded customer record LOOP AT it_customer INTO wa_customer. " Clear previous BDC data CLEAR it_bdcdata[]. " Build BDC data for screen input PERFORM bdc_dynpro USING 'ZBDC_SCREEN' '1000'. PERFORM bdc_field USING 'BDC_CURSOR' 'P_ORT01'. PERFORM bdc_field USING 'BDC_OKCODE' '=ONLI'. " Press Enter PERFORM bdc_field USING 'P_KUNNR' wa_customer-KUNNR. PERFORM bdc_field USING 'P_NAME' wa_customer-NAME1. PERFORM bdc_field USING 'P_ORT01' wa_customer-ORT01. " Optionally simulate pressing Exit or Back PERFORM bdc_dynpro USING 'ZBDC_SCREEN' '1000'. PERFORM bdc_field USING 'BDC_OKCODE' '/EE'. " Exit PERFORM bdc_field USING 'BDC_CURSOR' 'P_KUNNR'. " Call transaction with built BDC data in background mode CALL TRANSACTION 'ZBDC_CUS' USING it_bdcdata MODE 'N' " 'N' - Background, 'A' - Foreground, 'E' - Errors only UPDATE 'S'. " Synchronous update ENDLOOP. "--- Subroutine to declare dynpro screen --- FORM bdc_dynpro USING program screen. CLEAR wa_bdcdata. wa_bdcdata-program = program. wa_bdcdata-dynpro = screen. wa_bdcdata-dynbegin = 'X'. APPEND wa_bdcdata TO it_bdcdata. ENDFORM. "--- Subroutine to assign value to a field --- FORM bdc_field USING fnam fval. CLEAR wa_bdcdata. wa_bdcdata-fnam = fnam. wa_bdcdata-fval = fval. APPEND wa_bdcdata TO it_bdcdata. ENDFORM.</code></pre><P><STRONG>3. Difference Between CALL TRANSACTION and SESSION METHOD</STRONG></P><TABLE border="1" width="100%"><TBODY><TR><TD width="33.333333333333336%" height="30px"><STRONG>Aspect</STRONG></TD><TD width="33.333333333333336%" height="30px"><STRONG>CALL TRANSACTION</STRONG></TD><TD width="33.333333333333336%" height="30px"><STRONG>SESSION METHOD</STRONG></TD></TR><TR><TD width="33.333333333333336%" height="30px">Execution</TD><TD width="33.333333333333336%" height="30px">Immediate</TD><TD width="33.333333333333336%" height="30px">Deferred via SM35</TD></TR><TR><TD width="33.333333333333336%" height="30px">Error Handling</TD><TD width="33.333333333333336%" height="30px">Manual/Error log</TD><TD width="33.333333333333336%" height="30px">SM35 Session log</TD></TR><TR><TD width="33.333333333333336%" height="30px">Performance</TD><TD width="33.333333333333336%" height="30px">Faster, suitable for small data</TD><TD width="33.333333333333336%" height="30px">Better for large volumes</TD></TR><TR><TD width="33.333333333333336%" height="30px">Mode</TD><TD width="33.333333333333336%" height="30px">Foreground/Background/No Display</TD><TD width="33.333333333333336%" height="30px">Processes in background</TD></TR><TR><TD width="33.333333333333336%" height="30px">Data Volume</TD><TD width="33.333333333333336%" height="30px">Limited</TD><TD width="33.333333333333336%" height="30px">Handles large volumes efficiently</TD></TR></TBODY></TABLE><P><STRONG><BR /><BR /><BR /><BR /><BR /></STRONG></P><P><BR /><BR /></P> 2025-07-02T14:14:43.654000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/recap-sql-selection-patterns-in-sap-hana-database-presented-at-sap-inside/ba-p/14135601 Recap: SQL selection patterns in SAP HANA database, presented at SAP Inside Track Wroclaw 2025 2025-07-03T10:23:24.088000+02:00 Bogdan7 https://community.sap.com/t5/user/viewprofilepage/user-id/171709 <P><STRONG><SPAN>A couple of words about me:</SPAN></STRONG>   <SPAN>&nbsp;</SPAN></P> <P><SPAN>My name is Bogdan Brzozowski and I’m Managing Software Architect working for Capgemini Poland within</SPAN>&nbsp;more than 14 years. My current position encompasses the following responsibilities:</P> <UL> <LI><STRONG>Establishing architecture</STRONG> (ERD, UML) for ABAP based custom solutions to be implemented for our customers by our developers.</LI> <LI><STRONG>Reverse engineering</STRONG> of the legacy ABAP solutions belonging to our customers to take the full responsibility for their further development and maintenance.</LI> <LI>Conducting <STRONG>internal trainings</STRONG> for our technical consultants to improve their technical skills.</LI> <LI><STRONG>Presentations for external audience</STRONG> to make our company visible as top provider of SAP technology-based solutions.</LI> <LI><STRONG>Custom code conversion guidelines</STRONG> – I am responsible for creation and keeping this document up to date.</LI> <LI>Spreading knowledge about <STRONG>internal Capgemini data migration tools</STRONG> like Syniti or Concert Tool.</LI> </UL> <P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bb.JPG" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/282032i3DE7E9FB2A986A09/image-size/large?v=v2&amp;px=999" role="button" title="bb.JPG" alt="bb.JPG" /></span></P> <P>&nbsp;</P> <P><SPAN>&nbsp;</SPAN></P> <P><STRONG><SPAN>A couple of sentences about the event:</SPAN></STRONG> <SPAN>&nbsp;</SPAN></P> <P><SPAN>SAP Inside Track was held again in Wroclaw this year. That time we met on rainy Saturday day (7-JUNE-2025) in the premises of WBS Merito University - well known private university that was event co-organizer (together with Capgemini). We welcomed attendees from 9 countries, who were participating in the sessions conducted in English by 18 presenters. Most of the presentations were running in parallel split between 2 rooms.&nbsp; Predominant topics shared with the audience were related to the use of genAI in the context of SAP technologies. But there were also few sessions focusing on modern aspects of ABAP programming, like the subject presented in this blog :-).</SPAN></P> <P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="baner_SIT_2025.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/282033iD3B4B7DE6B9AD9FC/image-size/large?v=v2&amp;px=999" role="button" title="baner_SIT_2025.png" alt="baner_SIT_2025.png" /></span></P> <P>&nbsp;</P> <P><STRONG><SPAN>My Session:</SPAN></STRONG>   <SPAN>&nbsp;</SPAN></P> <P><SPAN>This year I had the opportunity to do a session called “ SQL selection patterns in CDS views examples”. Good practices are worth following and this is why design patterns like singleton, factory, prototype and many others became popular within object-oriented programming languages. The same may partially apply to data retrieval from any relational database. I noticed that there are typical&nbsp;techniques of data selection, that are useful in different projects for the customers from various branches: pharma, retail, automotive, utility supply to name few of them. In this blog I will share those selection patterns using syntax from ABAP Advanced Open SQL, ABAP CDS view entities and SQL script. HANA database is compliant with standard SQL ANSI 2016, so the examples presented in this blog may be useful to retrieve the data from other relational databases, which are compliant with SQL standard.. Below I would like to share main highlights, insights and key takeaways from my presentation.</SPAN> &nbsp;</P> <P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="inside.JPG" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/281004i71E43FB345D7BED8/image-size/large?v=v2&amp;px=999" role="button" title="inside.JPG" alt="inside.JPG" /></span></P> <P>Entity Relationship Diagram of the data model used for the code presented later on this blog.</P> <P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ERD.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/279412i69CB84939E3C4E22/image-size/large?v=v2&amp;px=999" role="button" title="ERD.png" alt="ERD.png" /></span></P> <P>Sales Order header is kept in VBAK table, while its items in VBAP. Additionally all the changes within Sales Order data are recorded in so called Change Documents with 2 main tables: CDHDR as the change header and CDPOS that stores old and new value of a given field. ERD diagram above uses well known crow's foot notation - see more details <A href="https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model#Crow's_foot_notation" target="_self" rel="nofollow noopener noreferrer">here.</A></P> <P>&nbsp;</P> <P><STRONG><SPAN>Main highlights and key takeaways :</SPAN></STRONG><STRONG> </STRONG> <SPAN>&nbsp;</SPAN></P> <P> I have presented 2 selection patterns for the <STRONG>performance</STRONG> improvement:</P> <UL> <LI><SPAN>exclusion</SPAN></LI> <LI><SPAN>&nbsp;case vs union all</SPAN></LI> </UL> <P><SPAN>...plus 2 <STRONG>functional</STRONG> patterns:</SPAN></P> <UL> <LI><SPAN>predecessor and successor</SPAN></LI> <LI><SPAN>data source determination during runtime.</SPAN></LI> </UL> <P>&nbsp;</P> <P><STRONG>Performance pattern: Exclusion</STRONG></P> <P>Let's take a look at ERD diagram again. Imagine the requirement to select all Sales Orders items (VBAP table), that do not refer to any material from MARA or they refer to materials of HAWA type only. (MARA-MTART = 'HAWA'). Additionally we are interested in Sales Orders of TA type only (VBAK-AUART = 'TA').</P> <P>The very first idea is the use of subquery embedded inside NOT EXISTS operator:</P> <pre class="lia-code-sample language-abap"><code>SELECT vbak~vbeln, vbap~posnr, vbap~matnr, vbap~netwr, vbap~waerk FROM vbak INNER JOIN vbap ON vbap~vbeln = vbak~vbeln WHERE vbak~auart = @cv_sd_order_type_ta AND NOT EXISTS ( SELECT @abap_true FROM mara AS subq WHERE subq~matnr = vbap~matnr AND subq~lvorm = @abap_false AND subq~mtart = @cv_material_type_hawa ) ORDER BY vbak~vbeln, vbap~posnr INTO CORRESPONDING FIELDS OF TABLE @me-&gt;mt_so_head_item[].</code></pre> <P>But subquery has 2 major disadvantages: it consumes a lot of database server resources (which is valid for any database provider: SAP, Oracle, MS, IBM, etc.) and it cannot be used in ABAP CDS view (valid for SAP HANA database only).</P> <P>The alternative offering much faster data retrieval is LEFT OUTER JOIN:</P> <pre class="lia-code-sample language-abap"><code>SELECT vbak~vbeln, vbap~posnr, vbap~matnr, vbap~netwr, vbap~waerk, mara~mtart, mara~xchpf FROM vbak INNER JOIN vbap ON vbap~vbeln = vbak~vbeln LEFT OUTER JOIN mara ON mara~matnr = vbap~matnr AND mara~lvorm = @ABAP_false "NOT in WHERE if OUTER join is expected WHERE vbak~auart = @CV_sd_order_type_ta AND ( mara~matnr IS NULL OR mara~mtart &lt;&gt; @CV_material_type_hawa ) ORDER BY vbak~vbeln, vbap~posnr INTO CORRESPONDING FIELDS OF TABLE @ME-&gt;mt_so_head_item[].</code></pre> <P>ATTENTION: any additional conditions against the data source from the left side of the outer join must be specified within ON operator, not as a part of WHERE clause. Otherwise you will transform your OUTER join (unintentionally) into the INNER join! You may get caught into this trap using&nbsp;<STRONG>Advanced</STRONG> Open SQL (with @ prefix when you refer to the variables declared in ABAP and residing on application server).&nbsp; Old Open SQL flavor for ABAP programming on ECC system (predecessor of S/4HANA) did not allow such implicit (and most likely unwanted) conversion of OUTER join into the INNER one.&nbsp;</P> <P>Association is not part of SQL standard, but it may be perceived like lazy outer join. This 'laziness' means that as long as ABAP app does not require the columns from the data source on the left side of the outer join, the database system does not perform outer join operation at all, saving some processing time and its resources. This is why we can use the similar technique to obtain data with our exclusion condition from the CDS view that uses association:</P> <pre class="lia-code-sample language-abap"><code>SELECT SalesOrder AS vbeln, so~\_Item-SalesOrderItem AS posnr, so~\_Item-Product AS matnr, so~\_Item-NetAmount AS netwr, so~\_Item-TransactionCurrency AS waerk, so~\_Item\_Product-ProductType AS mtart, so~\_Item\_Product-IsBatchManagementRequired AS xchpf FROM R_SalesOrderTP AS so WHERE so~SalesOrderType = @cv_sd_order_type_ta AND so~\_Item-SalesOrderItem IS NOT NULL AND ( so~\_Item\_Product-ProductType IS NULL OR ( so~\_Item\_Product-ProductType &lt;&gt; @cv_material_type_hawa AND so~\_Item\_Product-IsMarkedForDeletion = @abap_false ) ) ORDER BY vbeln, posnr INTO TABLE @me-&gt;mt_so_head_item[].</code></pre> <P><STRONG>Performance pattern: Case vs Union all</STRONG></P> <P>Imagine the following projection list using CASE operator:</P> <pre class="lia-code-sample language-abap"><code>SELECT SalesDocument AS vbeln, so~\_ItemBasic-SalesDocumentItem AS posnr, so~\_ItemBasic-Material AS matnr, so~\_ItemBasic-NetAmount AS netwr, so~\_ItemBasic-TransactionCurrency AS waerk, so~\_ItemBasic\_Material-MaterialType AS mtart, so~\_ItemBasic\_Material-IsBatchManagementRequired AS xchpf, CASE WHEN so~\_ItemBasic\_Material-IsBatchManagementRequired IS NULL THEN 'Batch Managment is IRRELEVANT' WHEN so~\_ItemBasic\_Material-IsBatchManagementRequired = @abap_true THEN 'Batch Managment IS required' ELSE 'Batch Managment is NOT required' END AS IsBatchMgmtReq FROM I_SalesDocumentBasic AS so WHERE so~SalesDocumentType = @cv_sd_order_type_ta AND so~\_ItemBasic-SalesDocumentItem IS NOT NULL AND ( so~\_ItemBasic\_Material-MaterialType &lt;&gt; @cv_material_type_hawa OR so~\_ItemBasic\_Material-MaterialType IS NULL ) ORDER BY vbeln, posnr INTO TABLE @me-&gt;mt_so_descriptive[].</code></pre> <P>It may be time consuming to execute, as it runs as a single thread on HANA database server. The alternative is to split such single SELECT statement into as many SELECT statements as many CASE conditions are used. All these SELECT statements will be combined with UNION ALL operator, like in the code below:</P> <pre class="lia-code-sample language-abap"><code>SELECT SalesDocument AS vbeln, so~\_ItemBasic-SalesDocumentItem AS posnr, so~\_ItemBasic-Material AS matnr, so~\_ItemBasic-NetAmount AS netwr, so~\_ItemBasic-TransactionCurrency AS waerk, so~\_ItemBasic\_Material-MaterialType AS mtart, so~\_ItemBasic\_Material-IsBatchManagementRequired AS xchpf, 'Batch Managment is IRRELEVANT' AS IsBatchMgmtReq FROM I_SalesDocumentBasic AS so WHERE so~SalesDocumentType = @cv_sd_order_type_ta AND so~\_ItemBasic-SalesDocumentItem IS NOT NULL AND ( so~\_ItemBasic\_Material-MaterialType &lt;&gt; @cv_material_type_hawa OR so~\_ItemBasic\_Material-MaterialType IS NULL ) AND so~\_ItemBasic\_Material-IsBatchManagementRequired IS NULL UNION ALL SELECT SalesDocument AS vbeln, so~\_ItemBasic-SalesDocumentItem AS posnr, so~\_ItemBasic-Material AS matnr, so~\_ItemBasic-NetAmount AS netwr, so~\_ItemBasic-TransactionCurrency AS waerk, so~\_ItemBasic\_Material-MaterialType AS mtart, so~\_ItemBasic\_Material-IsBatchManagementRequired AS xchpf, 'Batch Managment IS required' AS IsBatchMgmtReq FROM I_SalesDocumentBasic AS so WHERE so~SalesDocumentType = @cv_sd_order_type_ta AND so~\_ItemBasic-SalesDocumentItem IS NOT NULL AND ( so~\_ItemBasic\_Material-MaterialType &lt;&gt; @cv_material_type_hawa OR so~\_ItemBasic\_Material-MaterialType IS NULL ) AND so~\_ItemBasic\_Material-IsBatchManagementRequired = @abap_true UNION ALL SELECT SalesDocument AS vbeln, so~\_ItemBasic-SalesDocumentItem AS posnr, so~\_ItemBasic-Material AS matnr, so~\_ItemBasic-NetAmount AS netwr, so~\_ItemBasic-TransactionCurrency AS waerk, so~\_ItemBasic\_Material-MaterialType AS mtart, so~\_ItemBasic\_Material-IsBatchManagementRequired AS xchpf, 'Batch Managment is NOT required' AS IsBatchMgmtReq FROM I_SalesDocumentBasic AS so WHERE so~SalesDocumentType = @cv_sd_order_type_ta AND so~\_ItemBasic-SalesDocumentItem IS NOT NULL AND ( so~\_ItemBasic\_Material-MaterialType &lt;&gt; @cv_material_type_hawa OR so~\_ItemBasic\_Material-MaterialType IS NULL ) AND so~\_ItemBasic\_Material-IsBatchManagementRequired = @abap_false ORDER BY vbeln, posnr INTO TABLE @me-&gt;mt_so_descriptive[].</code></pre> <P>Each of 3 SELECT commands above contains respective conditions from the CASE operator used on the projection list of the single SELECT instruction. Such approach allows database system execute 3 separate threads in parallel and then combine their results via UNION ALL.&nbsp;&nbsp;</P> <P>ATTENTION: do not use UNION without ALL keyword, because the advantage of parallel processing may be overshadowed with additional effort to eliminate duplicates from the result set (mt_so_descriptive[] internal table in our example).&nbsp;</P> <P>&nbsp;</P> <P><STRONG>Functional pattern: predecessor and successor</STRONG></P> <P>Imagine the situation in which we need to provide old and new values of the given table field in chronological order. 2 main tables of Change Documents (CDHDR - header and CDPOS - position) store such information. Our goal is to retrieve the pairs of the values for a given field - the old value before the change (predecessor) and the new value saved as the result of the change (successor). Subquery seems to be inevitable option to achieve this functionality, so SQL script implemented in ABAP Managed Database Procedure (AMDP) global class is the way to go. But first let's prepare CDS view that joins CDHDR and CDPOS before programming in SQL script:</P> <pre class="lia-code-sample language-sql"><code>define view entity Z_I_CD with parameters iv_objclass : cdobjectcl, iv_tabname : tabname, iv_fldname : fieldname as select from cdhdr as hdr inner join cdpos as pos on pos.objectid = hdr.objectid and pos.changenr = hdr.changenr { key hdr.objectid, key hdr.changenr, key pos.tabkey, key pos.chngind, hdr.username, concat(hdr.udate, hdr.utime) as changed_on, pos.unit_old, pos.unit_new, pos.cuky_old, pos.cuky_new, pos.value_old, pos.value_new } where hdr.objectclas = $parameters.iv_objclass and pos.tabname = $parameters.iv_tabname and pos.fname = $parameters.iv_fldname</code></pre> <P>Another good practice used in the implementation above is the use of CDS view parameters: iv_objclass, iv_tabname and iv_fldname as we need to track the changes for the specific table field only. Concatenation of the date and time indicating when exactly the change occurred is crucial to build appropriate subquery in SQL script - see the field CHANGED_ON:</P> <pre class="lia-code-sample language-abap"><code>CLASS zcl_amdp_sel_pattern DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES : if_amdp_marker_hdb. CLASS-METHODS: read_cd_pair FOR TABLE FUNCTION z_f_cd_pair, read_toax FOR TABLE FUNCTION z_f_toax. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_amdp_sel_pattern IMPLEMENTATION. METHOD read_cd_pair BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING z_i_cd. lt_result = select cd.mandt, cd.objectid, cd.tabkey, cd.changenr, cd.chngind, cd.username, cd.changed_on, cd.unit_old, cd.unit_new, cd.cuky_old, cd.cuky_new, cd.value_old, cd.value_new, pred.username as pred_username, pred.changed_on as pred_changed_on, pred.unit_old as pred_unit_old, pred.unit_new as pred_unit_new, pred.cuky_old as pred_cuky_old, pred.cuky_new as pred_cuky_new, pred.value_old as pred_value_old, pred.value_new pred_value_new from z_i_cd( iv_objclass =&gt; :iv_objclass, iv_tabname =&gt; :iv_tabname, iv_fldname =&gt; :iv_fldname ) as cd left outer join z_i_cd( iv_objclass =&gt; :iv_objclass, iv_tabname =&gt; :iv_tabname, iv_fldname =&gt; :iv_fldname ) as pred on pred.mandt = cd.mandt and pred.objectid = cd.objectid and pred.tabkey = cd.tabkey and pred.changed_on = ( select MAX( cdlast.changed_on ) from z_i_cd( iv_objclass =&gt; :iv_objclass, iv_tabname =&gt; :iv_tabname, iv_fldname =&gt; :iv_fldname ) as cdlast where cdlast.objectid = cd.objectid and cdlast.tabkey = cd.tabkey and cdlast.changed_on &lt; cd.changed_on ); RETURN :lt_result; ENDMETHOD. ENDCLASS.</code></pre> <P>Optional predecessor (see alias PRED for Z_I_CD in <STRONG>outer</STRONG> join above) must have&nbsp; the greatest available value of the field CHANGED_ON but still lower than CHANGED_ON in successor entry (alias CD). Code available in github.com contains testing console class&nbsp; ZCL_SEL_PATTERN_TEST_CONSOLE that retrieves the pair of predecessor and successor with regard to the changes in VBAP-MATNR field (material of the Sales Order position).</P> <P>&nbsp;</P> <P><STRONG>Functional pattern: dynamic data source determination in CDS view</STRONG></P> <P>Dynamic data source determination <STRONG>in ABAP</STRONG> is a trivial task to implement:</P> <DIV> <DIV>&nbsp;</DIV> </DIV> <pre class="lia-code-sample language-abap"><code>DATA lt_toa01 TYPE STANDARD TABLE OF toa01. DATA(lv_table_name) = 'TOA01'. SELECT * FROM (lv_table_name) INTO TABLE @lt_toa01[].</code></pre> <P>Archive link tables like TOA01, TOA02, TOA03, etc. share identical structure, but based on the configuration each of these tables stores the links for the documents of different SAP objects. Implementing a similar solution in CDS view is not such straightforward topic. It is possible only via table function:&nbsp;</P> <pre class="lia-code-sample language-sql"><code>@EndUserText.label: 'Any TOA0x table' define table function Z_F_TOAX with parameters iv_table_name : tabname16 returns { mandt : abap.clnt; sap_object : saeanwdid; object_id : saeobjid; archiv_id : saearchivi; arc_doc_id : saeardoid; ar_object : saeobjart; ar_date : saeabadate; del_date : saedeldate; reserve : saereserve; } implemented by method zcl_amdp_sel_pattern=&gt;read_toax;</code></pre> <P>...and AMDP class:</P> <pre class="lia-code-sample language-abap"><code>METHOD read_toax BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING toa01. DECLARE lv_query STRING; DECLARE lt_result TABLE LIKE toa01; lv_query = 'SELECT * FROM ' || :iv_table_name; EXECUTE IMMEDIATE lv_query INTO lt_result; RETURN :lt_result; ENDMETHOD.</code></pre> <P>As we can see the whole trick is the use of EXECUTE IMMEDIATE command that SQL script offers. The source of data selection is delivered into AMDP method as input parameter iv_table_name.</P> <P> &nbsp;<SPAN>&nbsp;</SPAN></P> <P><STRONG><SPAN>Recommended resources for your readers to continue with your learning journey:</SPAN></STRONG><STRONG> </STRONG><STRONG>&nbsp;</STRONG></P> <P>Working code presented in this blog can be downloaded from here:</P> <P><A href="https://github.com/brbogdan/SQL-selection-patterns-in-S4" target="_blank" rel="noopener nofollow noreferrer">https://github.com/brbogdan/SQL-selection-patterns-in-S4</A></P> <P>&nbsp;</P> <P><STRONG><SPAN>Related community </SPAN></STRONG><SPAN><A href="https://community.sap.com/t5/all-sap-managed-tags/ct-p/managed-tags" target="_blank"><STRONG>managed tags</STRONG></A><STRONG> you should subscribe to remain informed about this topic:</STRONG></SPAN>   <SPAN>&nbsp;</SPAN></P> <P class=""><A title="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" target="_blank"><SPAN>ABAP Development</SPAN></A></P> <P class=""><A title="https://community.sap.com/t5/c-khhcw49343/SQL/pd-p/122888716930844301706258287775555" href="https://community.sap.com/t5/c-khhcw49343/SQL/pd-p/122888716930844301706258287775555" target="_blank"><SPAN>SQL</SPAN></A></P> <P>  </P> <P><STRONG><SPAN>Related community blog posts:</SPAN></STRONG>   <SPAN>&nbsp;</SPAN></P> <P class=""><A title="https://community.sap.com/t5/technology-blog-posts-by-members/cds-views-vs-traditional-abap-logic-performance/ba-p/14125726" href="https://community.sap.com/t5/technology-blog-posts-by-members/cds-views-vs-traditional-abap-logic-performance/ba-p/14125726" target="_blank">CDS Views Vs Traditional ABAP Logic Performance</A></P> <P class=""><SPAN><A title="https://community.sap.com/t5/technology-blog-posts-by-members/sql-scripts-in-sap-hana/ba-p/13738376" href="https://community.sap.com/t5/technology-blog-posts-by-members/sql-scripts-in-sap-hana/ba-p/13738376" target="_blank">SQL Scripts in SAP HANA</A></SPAN></P> <P><SPAN>&nbsp;</SPAN></P> <P><STRONG> </STRONG><STRONG><SPAN>How was the event for you?:</SPAN></STRONG>   <SPAN>&nbsp;</SPAN></P> <P> My session&nbsp; has gathered around 40 participants, who were acting interactively despite being a bit exhausted after big portion of the preceding sessions and rainy weather :-).&nbsp; I hope that some of them will have a chance to implement the patterns I shared on their commercial projects for their real customers.&nbsp;</P> <P>I have also benefited from this event taking part in some very impressive sessions:</P> <UL> <LI>Level up your CAP skills by learning how to use the cds REPL presented by DJ Adams&nbsp;<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/53">@qmacro</a>&nbsp;</LI> <LI>AI agents collaboration for SAP business processes using Google A2A protocol by Igor Narodowy&nbsp;</LI> <LI>Why is it becoming increasingly difficult to keep up with SAP? by Paweł Pawlak&nbsp;<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/136635">@PawelPawlak</a></LI> <LI>AI agents and SAP. What's the buzz? by Vitaliy Rudnytskiy&nbsp;<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/183">@Vitaliy-R</a>&nbsp;</LI> <LI>3D modeling in UI5 by Nico Schoenteich&nbsp;<a href="https://community.sap.com/t5/user/viewprofilepage/user-id/898">@nicoschoenteich</a>&nbsp;</LI> <LI>SAPdalf Crafts AI agents by Łukasz Skorwider</LI> <LI>SAP migrations and GenAI: pioneering the path forward by Tomasz Wilk</LI> </UL> <P>Many thanks to these speakers from me!    <SPAN>&nbsp;</SPAN></P> <P> </P> <P><STRONG><SPAN>Now let’s hear from you:</SPAN></STRONG>   <SPAN>&nbsp;</SPAN></P> <P><SPAN>Before ending the blog post I want to share that one of the things I enjoyed the most in SAP Inside Track Wroclaw 2025. It was meeting new people and old colleagues I haven't seen for a while . Who said this kind of fun needs to end in SAP Inside Track?:) Please introduce yourself in the comment’s section and share what you do in the world of SAP?&nbsp;</SPAN></P> <P>&nbsp;</P> 2025-07-03T10:23:24.088000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/splitstorm-a-generic-splitter-configuration-tool/ba-p/14143875 Splitstorm - A Generic Splitter Configuration Tool 2025-07-03T17:51:47.033000+02:00 EnnoWulff https://community.sap.com/t5/user/viewprofilepage/user-id/7046 <P>&nbsp;</P><H2 id="toc-hId-1734146665">Extracting and Restoring Splitter Container Configurations in SAP GUI with ABAP</H2><P>When working with complex SAP GUI applications, it's common to use CL_GUI_SPLITTER_CONTAINER to structure screens. These splitter configurations often evolve over time and differ between users, environments, or sSAPGUI-settings.</P><P>This article presents a simple but effective way to extract and later restore the current configuration of SAP splitter containers using a small local ABAP utility that I call <STRONG>SplitStorm</STRONG>.</P><P>The core idea is not product-related. It's about treating layout configurations as <STRONG>data</STRONG> that can be stored and restored. While SAP provides APIs to define and modify split containers, it lacks built-in support for introspection and persistence of these layout states.</P><H3 id="toc-hId-1666715879">Problem Statement</H3><P>There are a few typical situations where this becomes relevant:</P><UL><LI><P>Users have different SAPGUI settings (theme, fonts or fontsize) which results in different output and hidden information.&nbsp;</P></LI><LI>Different users have different interest on different areas. One user needs to have a bigger view on the global ALV-Grid, another colleague wants to see more of the detail view.</LI><LI>Different screen resolutions result in unused screen areas, e.g. when the ratio is set to 30% for the left object tree, what fits great on FullHD but is to much for higher resolutions or wide screens</LI></UL><H3 id="toc-hId-1470202374">Approach</H3><P>Using recursive traversal and some clever techniques, it’s possible to extract the layout structure and size ratios of a splitter hierarchy. The data is stored in a simple, format that can later be used to reconstruct the exact same configuration.</P><P>The main features include:</P><UL><LI><P>Reading the layout hierarchy of nested CL_GUI_SPLITTER_CONTAINER instances</P></LI><LI><P>Capturing the orientation, pane sizes, and nesting relationships</P></LI><LI><P>Rebuilding the structure with the same layout at a later time</P></LI></UL><H3 id="toc-hId-1273688869">How does it work?</H3><P>The method ANALYZE_AND_SAVE analyzes the container hierarchy of the given main container. To retrieve the number of rows and columns of a splitter, I simply try to get all containers in a 20x20-Grid. If I do not get a valid container for row 3 and column 4 then I know that there are max 2 rows or max 3 columns.</P><P>The height and width for each pane will be read and stored in a simple matrix information</P><P>Data will be saved in the Index-Table INDX where data in any format can be stored easily. A better way would be to transform the data to JSON or serialize in a data object and store it in an own table. But for my purposes I think that INDX is okay.</P><P>Restoring the data reads the path to the current container and sets height and width.&nbsp;</P><P>It's easy to build the standard layout and the restore the configuration from saved data.</P><H3 id="toc-hId-1077175364">The Code</H3><P>The actual complete source code is available at github: <A href="https://github.com/tricktresor/splitstorm" target="_self" rel="nofollow noopener noreferrer">Splitstorm</A></P><H4 id="toc-hId-1009744578">Demo report</H4><P>The Demo report builds a sample configuration using splitter containers without any controls in it.</P><P>You can save the current configuration, load or delete an existing layout.</P><pre class="lia-code-sample language-abap"><code>REPORT zt9r_splitstorm_demo01. SELECTION-SCREEN PUSHBUTTON /1(20) TEXT-sav USER-COMMAND zsave. SELECTION-SCREEN PUSHBUTTON /1(20) TEXT-lod USER-COMMAND zload. SELECTION-SCREEN PUSHBUTTON /1(20) TEXT-del USER-COMMAND zdelete. INITIALIZATION. DATA(docker) = NEW cl_gui_docking_container( ratio = 90 side = cl_gui_docking_container=&gt;dock_at_bottom ). DATA(sca) = NEW cl_gui_splitter_container( parent = docker rows = 2 columns = 2 ). DATA(sca1) = NEW cl_gui_splitter_container( parent = sca-&gt;get_container( row = 1 column = 1 ) rows = 1 columns = 2 ). DATA(sca2) = NEW cl_gui_splitter_container( parent = sca-&gt;get_container( row = 2 column = 1 ) rows = 2 columns = 1 ). DATA(scb1) = NEW cl_gui_splitter_container( parent = sca2-&gt;get_container( row = 1 column = 1 ) rows = 1 columns = 2 ). DATA(scb2) = NEW cl_gui_splitter_container( parent = sca2-&gt;get_container( row = 2 column = 1 ) rows = 2 columns = 1 ). AT SELECTION-SCREEN. DATA(info) = NEW zt9r_splitstorm( sy-cprog ). CASE sy-ucomm. WHEN 'ZSAVE'. info-&gt;analyze_and_save( docker ). WHEN 'ZLOAD'. info-&gt;load_and_restore( docker ). WHEN 'ZDELETE'. info-&gt;delete( ). ENDCASE.</code></pre><H4 id="toc-hId-813231073">Main class</H4><pre class="lia-code-sample language-abap"><code>CLASS zt9r_splitstorm DEFINITION PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_splitter_info, path TYPE string, rows TYPE i, columns TYPE i, row_heights TYPE STANDARD TABLE OF i WITH DEFAULT KEY, column_widths TYPE STANDARD TABLE OF i WITH DEFAULT KEY, END OF ty_splitter_info. TYPES ty_splitter_info_tab TYPE STANDARD TABLE OF ty_splitter_info WITH DEFAULT KEY. METHODS delete. METHODS load_and_restore IMPORTING i_container TYPE REF TO cl_gui_container. METHODS analyze_and_save IMPORTING i_container TYPE REF TO cl_gui_container. METHODS constructor IMPORTING repid TYPE clike. PRIVATE SECTION. METHODS save. METHODS load. CONSTANTS mc_root TYPE string VALUE `ROOT`. METHODS analyze_recursive IMPORTING i_container TYPE REF TO cl_gui_control i_path TYPE string RETURNING VALUE(result) TYPE abap_bool. METHODS get_row_count IMPORTING i_splitter TYPE REF TO cl_gui_splitter_container RETURNING VALUE(result) TYPE i. METHODS get_column_count IMPORTING i_splitter TYPE REF TO cl_gui_splitter_container RETURNING VALUE(result) TYPE i. METHODS restore_recursive IMPORTING i_container TYPE REF TO cl_gui_control i_path TYPE string. METHODS get_splitter_row_height IMPORTING io_splitter TYPE REF TO cl_gui_splitter_container RETURNING VALUE(r_size) TYPE i. METHODS get_splitter_col_width IMPORTING io_splitter TYPE REF TO cl_gui_splitter_container RETURNING VALUE(r_size) TYPE i. METHODS analyze IMPORTING i_container TYPE REF TO cl_gui_container RETURNING VALUE(result) TYPE ty_splitter_info_tab. METHODS restore_sizes IMPORTING i_container TYPE REF TO cl_gui_container. METHODS get_id RETURNING VALUE(r_id) TYPE char20. DATA size_info TYPE ty_splitter_info_tab. DATA repid TYPE c LENGTH 40. ENDCLASS. CLASS ZT9R_SPLITSTORM IMPLEMENTATION. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;ANALYZE * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER * | [&lt;-()] RESULT TYPE TY_SPLITTER_INFO_TAB * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD analyze. LOOP AT i_container-&gt;children INTO DATA(child). analyze_recursive( i_container = child i_path = mc_root ). ENDLOOP. result = size_info. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Public Method ZT9R_SPLITSTORM-&gt;ANALYZE_AND_SAVE * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD analyze_and_save. analyze( i_container = i_container ). save( ). ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;ANALYZE_RECURSIVE * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTROL * | [---&gt;] I_PATH TYPE STRING * | [&lt;-()] RESULT TYPE ABAP_BOOL * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD analyze_recursive. TRY. DATA(lo_splitter) = CAST cl_gui_splitter_container( i_container ). result = abap_true. CATCH cx_sy_move_cast_error. result = abap_false. RETURN. ENDTRY. DATA(lv_rows) = get_row_count( lo_splitter ). DATA(lv_columns) = get_column_count( lo_splitter ). DATA lt_row_heights TYPE STANDARD TABLE OF i WITH DEFAULT KEY. DATA lt_col_widths TYPE STANDARD TABLE OF i WITH DEFAULT KEY. DO lv_rows TIMES. APPEND get_splitter_row_height( lo_splitter ) TO lt_row_heights. ENDDO. DO lv_columns TIMES. APPEND get_splitter_col_width( lo_splitter ) TO lt_col_widths. ENDDO. APPEND VALUE ty_splitter_info( path = i_path rows = lv_rows columns = lv_columns row_heights = lt_row_heights column_widths = lt_col_widths ) TO size_info. DATA(index_row) = 0. DATA(index_col) = 0. DO lv_rows TIMES. index_col = 0. index_row = index_row + 1. DO lv_columns TIMES. index_col = index_col + 1. DATA(lo_container) = lo_splitter-&gt;get_container( row = index_row column = index_col ). LOOP AT lo_container-&gt;children INTO DATA(lo_child). IF NOT analyze_recursive( i_container = lo_child i_path = |{ i_path }[{ index_row },{ index_col }]| ). EXIT. " from do ENDIF. ENDLOOP. ENDDO. ENDDO. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Public Method ZT9R_SPLITSTORM-&gt;CONSTRUCTOR * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] REPID TYPE CLIKE * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD constructor. me-&gt;repid = repid. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Public Method ZT9R_SPLITSTORM-&gt;DELETE * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD delete. DATA(id) = get_id( ). DELETE FROM DATABASE indx(z1) ID id. IF sy-subrc = 0 AND size_info IS NOT INITIAL. MESSAGE 'Splitter configuration deleted' TYPE 'S'. ENDIF. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;GET_COLUMN_COUNT * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER * | [&lt;-()] RESULT TYPE I * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD get_column_count. result = 0. DO 20 TIMES. DATA(container) = i_splitter-&gt;get_container( row = 1 column = sy-index ). IF container IS INITIAL. RETURN. ELSE. result = result + 1. ENDIF. ENDDO. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;GET_ID * +-------------------------------------------------------------------------------------------------+ * | [&lt;-()] R_ID TYPE CHAR20 * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD get_id. r_id = |SPLITTER-{ repid }-{ sy-uname }|. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;GET_ROW_COUNT * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER * | [&lt;-()] RESULT TYPE I * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD get_row_count. result = 0. DO 20 TIMES. DATA(container) = i_splitter-&gt;get_container( row = sy-index column = 1 ). IF container IS INITIAL. RETURN. ELSE. result = result + 1. ENDIF. ENDDO. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;GET_SPLITTER_COL_WIDTH * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] IO_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER * | [&lt;-()] R_SIZE TYPE I * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD get_splitter_col_width. io_splitter-&gt;get_column_width( EXPORTING id = sy-index IMPORTING result = r_size ). cl_gui_cfw=&gt;flush( ). ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;GET_SPLITTER_ROW_HEIGHT * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] IO_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER * | [&lt;-()] R_SIZE TYPE I * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD get_splitter_row_height. io_splitter-&gt;get_row_height( EXPORTING id = sy-index IMPORTING result = r_size ). cl_gui_cfw=&gt;flush( ). ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;LOAD * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD load. DATA(id) = get_id( ). IMPORT splitter_info TO size_info FROM DATABASE indx(z1) ID id. IF sy-subrc = 0 AND size_info IS NOT INITIAL. MESSAGE 'Splitter configuration loaded' TYPE 'S'. ENDIF. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Public Method ZT9R_SPLITSTORM-&gt;LOAD_AND_RESTORE * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD load_and_restore. load( ). restore_sizes( i_container = i_container ). ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;RESTORE_RECURSIVE * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTROL * | [---&gt;] I_PATH TYPE STRING * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD restore_recursive. TRY. DATA(splitter) = CAST cl_gui_splitter_container( i_container ) ##NO_TEXT. CATCH cx_sy_move_cast_error. RETURN. ENDTRY. READ TABLE size_info INTO DATA(info) WITH KEY path = i_path. IF sy-subrc &lt;&gt; 0 OR splitter IS INITIAL. RETURN. ENDIF. DATA(idx) = 1. LOOP AT info-row_heights INTO DATA(lv_r). splitter-&gt;set_row_height( id = idx height = lv_r ). idx = idx + 1. ENDLOOP. idx = 1. LOOP AT info-column_widths INTO DATA(lv_c). splitter-&gt;set_column_width( id = idx width = lv_c ). idx = idx + 1. ENDLOOP. " Rekursiv weiter DATA(index_row) = 0. DATA(index_col) = 0. DO info-rows TIMES. index_col = 0. index_row = index_row + 1. DO info-columns TIMES. index_col = index_col + 1. DATA(lo_container) = splitter-&gt;get_container( row = index_row column = index_col ). DATA(lv_subpath) = |{ i_path }[{ index_row },{ index_col }]|. LOOP AT lo_container-&gt;children INTO DATA(lo_child). restore_recursive( i_container = lo_child i_path = lv_subpath ). ENDLOOP. ENDDO. ENDDO. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;RESTORE_SIZES * +-------------------------------------------------------------------------------------------------+ * | [---&gt;] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD restore_sizes. IF size_info IS INITIAL. RETURN. ENDIF. LOOP AT i_container-&gt;children INTO DATA(child). restore_recursive( i_container = child i_path = mc_root ). ENDLOOP. ENDMETHOD. * &lt;SIGNATURE&gt;---------------------------------------------------------------------------------------+ * | Instance Private Method ZT9R_SPLITSTORM-&gt;SAVE * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------&lt;/SIGNATURE&gt; METHOD save. IF size_info IS INITIAL. RETURN. ENDIF. DATA(id) = get_id( ). EXPORT splitter_info FROM size_info TO DATABASE indx(z1) ID id. MESSAGE 'Splitter configuration saved' TYPE 'S'. ENDMETHOD. ENDCLASS.</code></pre><P>&nbsp;</P> 2025-07-03T17:51:47.033000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/replace-all-occurrences-in-multiple-fields-of-an-internal-table/ba-p/14137810 Replace All Occurrences in Multiple Fields of an Internal Table 2025-07-04T18:13:43.456000+02:00 manijangiti https://community.sap.com/t5/user/viewprofilepage/user-id/2174619 <P><U><STRONG><BR /></STRONG></U>This blog provides a smart way to clean special characters like @, #, !, and , from internal table data.<BR />It helps when exporting data to CSV files, especially for AL11 directory usage.<BR />Instead of writing code for each field, we clean all fields in one loop using field symbols.<BR />RTTI (Runtime Type Info) is used to make it dynamic for any table.<BR />This makes your exported data neat, clean, and ready for use.<BR /><U><STRONG><BR />Before Replacing<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="2a8f888a-14ee-47a0-8ca4-938a766ae396.jpg" style="width: 800px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/279339i76864E73FEF115C7/image-size/large?v=v2&amp;px=999" role="button" title="2a8f888a-14ee-47a0-8ca4-938a766ae396.jpg" alt="2a8f888a-14ee-47a0-8ca4-938a766ae396.jpg" /></span><BR /><BR /></STRONG></U><FONT color="#000000"><STRONG>Code :</STRONG></FONT></P><pre class="lia-code-sample language-abap"><code>REPORT ZREPLACE_INTERNAL_TABLE. "Define structure TY_DATA for sample person data TYPES: BEGIN OF TY_DATA, NAME TYPE STRING, CITY TYPE STRING, EMAIL TYPE STRING, ADDRESS TYPE STRING, COMMENTS TYPE STRING, END OF TY_DATA. "Internal table and work area to hold the data DATA: LT_DATA TYPE TABLE OF TY_DATA, LS_DATA TYPE TY_DATA. "Reference for SALV display DATA: LT_FACTORTY TYPE REF TO CL_SALV_TABLE. "Sample data containing unwanted characters: @, #, !, , LT_DATA = VALUE #( ( name = 'Mani@ Yadav!' city = 'Hydera#bad' email = 'mani@yadav@example.com' address = 'Road No, 1, Banjara Hills' comments = 'Good@ Person!' ) ( name = 'Anil Kumar' city = 'Mum#bai' email = 'anil.kumar@exa!mple.com' address = 'Apt@ 123, Green Society' comments = 'Very# Good, Employee' ) ( name = 'Ravi Teja!' city = 'Hyder@abad' email = 'ravi.teja#@example.com' address = 'Street 45, Jubilee@ Hills' comments = 'Nice, and Reliable!' ) ( name = 'Sushil Kumar' city = 'Chen@nai' email = 'sushil@kumar@example.com' address = 'Block 7, Ap@artment 3' comments = 'Great, Wo!rker' ) ( name = 'Kavita@ Lal' city = 'Pune, City' email = 'kavita.lal#@example.com' address = 'MG Road@, Sector 2!' comments = 'Smart and@ Intellig!ent' ) ( name = 'Arjun Mehta' city = 'Kolkata' email = 'arjun!mehta@example.com' address = 'Sector 9@, Block B' comments = 'Honest@ and Helpful!' ) ( name = 'Deepa Agarwal#' city = 'Jai!pur' email = 'deepa@agarwal@example.com' address = 'Colony 5@, Lane 3' comments = 'Re#liable Friend!' ) ( name = 'Vikrant Singh' city = 'Goa! Beach@' email = 'vikrant@singh#@example.com' address = 'Villa 22, P@alolem' comments = 'Social@ Worker#' ) ( name = 'Neha Sharma' city = 'Ind@ore# MP!' email = 'neha@sharma@example.com' address = 'Home@ 98, New Town!' comments = 'Quick@ L!ear#ner' ) ( name = 'Priya! Verma' city = 'De@lhi' email = 'priya.verma@example.com' address = 'Flat 12B, Lotus En@clave!' comments = 'Team, Play#er!' ) ). "Characters we want to remove from all fields DATA: LT_UNWANTED TYPE STANDARD TABLE OF STRING WITH EMPTY KEY, LV_CHAR TYPE STRING. APPEND '@' TO LT_UNWANTED. APPEND '#' TO LT_UNWANTED. APPEND '!' TO LT_UNWANTED. APPEND ',' TO LT_UNWANTED. FIELD-SYMBOLS: &lt;FS_DATA&gt; TYPE ANY, &lt;FS_FIELD&gt; TYPE ANY. "Loop through each row in the internal table LOOP AT LT_DATA ASSIGNING &lt;FS_DATA&gt;. "Get runtime structure description using RTTI DATA(LO_TABLE_DESCR) = CAST CL_ABAP_TABLEDESCR( CL_ABAP_TYPEDESCR=&gt;DESCRIBE_BY_DATA( LT_DATA ) ). DATA(LO_LINE_DESCR) = CAST CL_ABAP_STRUCTDESCR( LO_TABLE_DESCR-&gt;GET_TABLE_LINE_TYPE( ) ). DATA(LT_COMPONENTS) = LO_LINE_DESCR-&gt;COMPONENTS. "Loop through each field in the structure LOOP AT LT_COMPONENTS INTO DATA(LS_COMPONENT). ASSIGN COMPONENT LS_COMPONENT-NAME OF STRUCTURE &lt;FS_DATA&gt; TO &lt;FS_FIELD&gt;. "Replace all unwanted characters with space IF SY-SUBRC = 0 AND &lt;FS_FIELD&gt; IS ASSIGNED. LOOP AT LT_UNWANTED INTO LV_CHAR. REPLACE ALL OCCURRENCES OF LV_CHAR IN &lt;FS_FIELD&gt; WITH ' '. ENDLOOP. ENDIF. ENDLOOP. ENDLOOP. "Display the cleaned internal table using SALV Grid CALL METHOD CL_SALV_TABLE=&gt;FACTORY IMPORTING R_SALV_TABLE = LT_FACTORTY CHANGING T_TABLE = LT_DATA. LT_FACTORTY-&gt;DISPLAY( ). "Debugger breakpoint for inspection (optional) BREAK-POINT.</code></pre><P><BR /><U><EM><STRONG>Final Output after Replacing</STRONG></EM></U></P><P><U><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ce85d46a-cb8e-4e6e-8755-ad6b2181d0b7.jpg" style="width: 800px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/279341iD103B87DA4BC43CB/image-size/large?v=v2&amp;px=999" role="button" title="ce85d46a-cb8e-4e6e-8755-ad6b2181d0b7.jpg" alt="ce85d46a-cb8e-4e6e-8755-ad6b2181d0b7.jpg" /></span><BR /><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a>&nbsp;<BR /><BR /></STRONG></U></P> 2025-07-04T18:13:43.456000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/factory-alv-with-header-logo-and-footer-in-abap/ba-p/14145038 FACTORY ALV with Header , Logo and Footer in ABAP 2025-07-05T11:39:33.748000+02:00 vinodkumarreddyappannagari https://community.sap.com/t5/user/viewprofilepage/user-id/2174225 <P>I’m excited to share my very first blog post on SAP ABAP programming! In this post, you'll learn how to create an <STRONG>ALV</STRONG> report using the <STRONG>Factory Method</STRONG>, complete with a custom header, logo, and footer to enhance your report’s appearance and professionalism.</P><P>1. Create Logo&nbsp;</P><P>step1 : Go to <STRONG>OAER</STRONG>&nbsp; T code .</P><P>step2 :&nbsp;<SPAN>Enter the following fields for your logo.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_2-1751700892463.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/282961iEEB213D2ED2C2DD8/image-size/medium?v=v2&amp;px=400" role="button" title="vinodkumarreddyappannagari_2-1751700892463.png" alt="vinodkumarreddyappannagari_2-1751700892463.png" /></span></P><P><SPAN>Step 3: Click on Execute.</SPAN><BR /><BR /><SPAN>Step 4: Below screen will displayed, double click on Standard Doc Types.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="vinodkumarreddyappannagari_3-1751700948601.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/282963i889F288020A41685/image-size/medium?v=v2&amp;px=400" role="button" title="vinodkumarreddyappannagari_3-1751700948601.png" alt="vinodkumarreddyappannagari_3-1751700948601.png" /></span></P><P><SPAN>Step 5: Double Click on a screen and select the picture from your files you want make logo.</SPAN></P><P>&nbsp;</P><pre class="lia-code-sample language-abap"><code>REPORT ZVA_HEADER_LOGO_FACTORY. * Declare table reference TABLES: ZVA_VENDOR_TA. * Declare data references DATA: LT_TABLE TYPE REF TO CL_SALV_TABLE, " Reference to ALV table object LV_TEXT TYPE STRING. " Text string for header * Selection screen for Vendor Numbers SELECT-OPTIONS: S_VENO FOR ZVA_VENDOR_TA-VENDERNO. START-OF-SELECTION. * Select data from custom vendor table based on selection SELECT VENDERNO, NAME, CITY, POSTALCODE, EMAIL, ACCOUNTGROUP, PROCESSORGROUP, POSTINGBLOCK INTO TABLE <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1407137">@DATA</a>(LT_VENDOR) FROM ZVA_VENDOR_TA WHERE VENDERNO IN @S_VENO. * Proceed only if records are found IF LT_VENDOR IS NOT INITIAL. * Create the SALV (ALV) object using factory method CL_SALV_TABLE=&gt;FACTORY( IMPORTING R_SALV_TABLE = LT_TABLE CHANGING T_TABLE = LT_VENDOR ). * Create layout grids and logo objects for header and footer customization DATA(LT_LAYOUT) = NEW CL_SALV_FORM_LAYOUT_GRID( ). DATA(LT_LAYOUT1) = NEW CL_SALV_FORM_LAYOUT_GRID( ). DATA(LT_LOGO) = NEW CL_SALV_FORM_LAYOUT_LOGO( ). * Set the header title LV_TEXT = 'VINOD KUMAR REDDY'. LT_LAYOUT-&gt;CREATE_HEADER_INFORMATION( EXPORTING ROW = 3 COLUMN = 1 TEXT = LV_TEXT ). * Add user name label and text LT_LAYOUT-&gt;CREATE_LABEL( EXPORTING ROW = 5 COLUMN = 1 TEXT = 'User Name' ). LT_LAYOUT-&gt;CREATE_TEXT( EXPORTING ROW = 5 COLUMN = 2 TEXT = 'VINOD APPANNAGARI' ). * Add date label and current date value LT_LAYOUT-&gt;CREATE_LABEL( EXPORTING ROW = 3 COLUMN = 1 TEXT = 'Date' ). LT_LAYOUT-&gt;CREATE_TEXT( EXPORTING ROW = 3 COLUMN = 2 TEXT = SY-DATUM ). * Add time label and current system time LT_LAYOUT-&gt;CREATE_LABEL( EXPORTING ROW = 4 COLUMN = 1 TEXT = 'Time' ). LT_LAYOUT-&gt;CREATE_TEXT( EXPORTING ROW = 4 COLUMN = 2 TEXT = SY-UZEIT ). * Add footer layout - number of records found LT_LAYOUT1-&gt;CREATE_LABEL( EXPORTING ROW = 2 COLUMN = 1 TEXT = 'Number of records found' ). DATA: LV_COUNT TYPE INT4. DESCRIBE TABLE LT_VENDOR LINES LV_COUNT. LT_LAYOUT1-&gt;CREATE_TEXT( EXPORTING ROW = 2 COLUMN = 2 TEXT = LV_COUNT TOOLTIP = LV_COUNT ). * Set SAP logo on the right of the header LT_LOGO-&gt;SET_RIGHT_LOGO( 'SAPLOGO1' ). * Set header and footer content LT_LOGO-&gt;SET_LEFT_CONTENT( LT_LAYOUT ). LT_TABLE-&gt;SET_TOP_OF_LIST( VALUE = LT_LOGO ). LT_TABLE-&gt;SET_END_OF_LIST( VALUE = LT_LAYOUT1 ). * Display the ALV table LT_TABLE-&gt;DISPLAY( ). ENDIF.</code></pre><P>Output:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="cfc5871a-34dc-41eb-80e5-53adde9181b4.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/282954iE3A4C02EEF1754EF/image-size/large?v=v2&amp;px=999" role="button" title="cfc5871a-34dc-41eb-80e5-53adde9181b4.png" alt="cfc5871a-34dc-41eb-80e5-53adde9181b4.png" /></span></P><P><a href="https://community.sap.com/t5/c-khhcw49343/ABAP+Development/pd-p/833755570260738661924709785639136" class="lia-product-mention" data-product="314-1">ABAP Development</a>&nbsp;</P> 2025-07-05T11:39:33.748000+02:00 https://community.sap.com/t5/technology-blog-posts-by-members/sap-rap-events-custom-logic-without-badis-or-user-exits/ba-p/14146769 🚀 SAP RAP Events: Custom Logic Without BAdIs or User Exits 2025-07-08T08:49:47.512000+02:00 SimTshaba https://community.sap.com/t5/user/viewprofilepage/user-id/1693481 <P>As SAP S/4HANA continues to evolve with <STRONG>clean core</STRONG> principles, the <STRONG>ABAP RESTful Application Programming Model (RAP)</STRONG> is taking center stage. One of the most <STRONG>underused but powerful features</STRONG> of RAP is its <STRONG>event-based architecture</STRONG>, which allows you to plug in custom logic in a clean and upgrade-safe way.</P><P>Today, I want to share how you can <STRONG>listen to standard RAP events and trigger your own custom events</STRONG> — <STRONG>no BAdIs or user exits needed!</STRONG></P><HR /><H2 id="toc-hId-1734235050">🧠 The Concept: RAP Event Listeners</H2><P>In classic SAP ABAP, you’d typically write enhancements using:</P><UL><LI><P><span class="lia-unicode-emoji" title=":wrench:">🔧</span> BAdIs</P></LI><LI><P><span class="lia-unicode-emoji" title=":counterclockwise_arrows_button:">🔄</span> User exits</P></LI><LI><P><span class="lia-unicode-emoji" title=":light_bulb:">💡</span> Implicit enhancements</P></LI></UL><P>But in RAP, you can <STRONG>react to standard business behavior via events</STRONG>. That means you can write your own <STRONG>custom logic</STRONG> that responds when something happens in a <STRONG>standard RAP BO (Business Object)</STRONG> — like a purchase order being approved — by <STRONG>listening to its published events</STRONG>.</P><P>This is <STRONG>cleaner, future-proof, and doesn't modify the standard codebase.</STRONG></P><HR /><H2 id="toc-hId-1537721545"><span class="lia-unicode-emoji" title=":direct_hit:">🎯</span> Real Use Case</H2><P>Let’s say SAP’s standard BO for PurchaseOrder publishes an event when a PO is <STRONG>approved</STRONG>. You want to send a custom email, update another Z table, or trigger integration — <EM>only</EM> when that event happens.</P><H3 id="toc-hId-1470290759"><span class="lia-unicode-emoji" title=":white_heavy_check_mark:">✅</span> In RAP, you can do this like so:</H3><UL><LI><P>Step 1: The standard RAP object publishes the approval event (<STRONG><U>R_PurchaseOrderTP</U></STRONG>)</P></LI><LI><P>Step 2: Your <STRONG>custom RAP behavior definition</STRONG> listens for that event.</P></LI><LI><P>Step 3: You trigger a <STRONG>custom implementation</STRONG>, e.g., a mail sender class or integration call.</P></LI></UL><P>No BAdI. No user exit. No modifications.</P><HR /><H2 id="toc-hId-1144694535"><span class="lia-unicode-emoji" title=":framed_picture:">🖼</span>️ Illustration: RAP Event Flow</H2><H3 id="toc-hId-1077263749"><STRONG>Figure 1: Listening to Standard RAP Events in a Custom BO</STRONG></H3><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChatGPT Image Jul 8, 2025, 08_40_11 AM.png" style="width: 666px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/283797i66EB5A340CAD1889/image-size/large?v=v2&amp;px=999" role="button" title="ChatGPT Image Jul 8, 2025, 08_40_11 AM.png" alt="ChatGPT Image Jul 8, 2025, 08_40_11 AM.png" /></span></P><DIV class=""><DIV class=""><SPAN><span class="lia-unicode-emoji" title=":hammer_and_wrench:">🛠</span>️ How to Implement</SPAN></DIV></DIV><P>Here’s a simplified code sketch of how this works:</P><H3 id="toc-hId-880750244">1. <STRONG>Listen to Standard Event in Custom BO</STRONG></H3><DIV><DIV><P><SPAN>CLASS</SPAN> <SPAN>zcl_po_ext</SPAN><SPAN> DEFINITION</SPAN></P><P><SPAN>PUBLIC ABSTRACT FINAL</SPAN></P><P><SPAN>FOR EVENTS OF </SPAN><SPAN>R_PurchaseOrderTP</SPAN><SPAN>.</SPAN></P><P><SPAN>PUBLIC SECTION.</SPAN></P><P><SPAN>PROTECTED SECTION.</SPAN></P><P><SPAN>PRIVATE SECTION.</SPAN></P><P><SPAN>ENDCLASS</SPAN><SPAN>.</SPAN></P></DIV></DIV><H3 id="toc-hId-684236739">2. <STRONG>Handle the Event in Your Class</STRONG></H3><DIV><DIV><P><SPAN>CLASS</SPAN> <SPAN>lhe_po_ext</SPAN><SPAN> DEFINITION INHERITING FROM </SPAN><SPAN>cl_abap_behavior_event_handler</SPAN><SPAN>.</SPAN></P><P><SPAN>PRIVATE SECTION.</SPAN></P><P><SPAN>METHODS </SPAN><SPAN>on_approved</SPAN><SPAN> FOR ENTITY EVENT</SPAN></P><P><SPAN>approved</SPAN><SPAN> FOR </SPAN><SPAN>purchaseorder</SPAN><SPAN>~</SPAN><SPAN>approved</SPAN><SPAN>.</SPAN></P><P><SPAN>ENDCLASS.</SPAN></P></DIV></DIV><H3 id="toc-hId-487723234"><SPAN>You’re done — and you didn’t need to touch a single line of standard code!</SPAN></H3><HR /><H2 id="toc-hId-162127010"><span class="lia-unicode-emoji" title=":light_bulb:">💡</span> Why This Matters</H2><UL><LI><P><span class="lia-unicode-emoji" title=":locked:">🔒</span> <STRONG>Clean Core Compliant</STRONG> – Stay upgrade-safe.</P></LI><LI><P><span class="lia-unicode-emoji" title=":high_voltage:">⚡</span> <STRONG>No Enhancements or BAdIs Needed</STRONG> – Simpler architecture.</P></LI><LI><P>🧱 <STRONG>Composable</STRONG> – Build logic modularly using RAP principles.</P></LI><LI><P><span class="lia-unicode-emoji" title=":repeat_button:">🔁</span> <STRONG>Reusability</STRONG> – Listen to multiple events, reuse handlers across objects.</P></LI></UL><HR /><H2 id="toc-hId--34386495"><span class="lia-unicode-emoji" title=":megaphone:">📣</span> Final Thoughts</H2><P>The RAP event mechanism offers a <STRONG>paradigm shift</STRONG> in how we build custom logic in SAP. It allows us to be <STRONG>event-driven</STRONG>, <STRONG>clean</STRONG>, and <STRONG>compliant with SAP's future direction</STRONG>.</P><P>If you’re developing on S/4HANA or looking to modernize your ABAP stack — <STRONG>RAP events are your secret weapon</STRONG>.</P><P><span class="lia-unicode-emoji" title=":eyes:">👀</span> Have you tried this approach in your projects? I’d love to hear your experience. Let’s connect and share ideas!</P><HR /><P><span class="lia-unicode-emoji" title=":link:">🔗</span> #SAPRAP #CleanCore #S4HANA #ABAP #SAPDevelopers #NoMoreBADIs #EventDrivenArchitecture</P> 2025-07-08T08:49:47.512000+02:00