https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/ABAP-RESTful-Application-Programming-Model-blog-posts.xmlSAP Community - ABAP RESTful Application Programming Model2025-01-22T06:00:05.758288+00:00python-feedgenABAP RESTful Application Programming Model blog posts in SAP Communityhttps://community.sap.com/t5/technology-blogs-by-sap/derived-events-how-to-trigger-custom-event-from-an-sap-standard-event/ba-p/13955193Derived Events- How to Trigger Custom Event from an SAP Standard Event2024-12-04T11:42:10.468000+01:00SafaBahooshhttps://community.sap.com/t5/user/viewprofilepage/user-id/763514<P>In my previous blog post, we saw how one can <A href="https://community.sap.com/t5/technology-blogs-by-sap/add-custom-context-attributes-for-sap-released-event-types/ba-p/13940929" target="_blank">Add Custom Context Attributes for SAP Released Event Types</A>. From <A href="https://community.sap.com/t5/technology-blogs-by-sap/sap-btp-abap-environment-release-2308/ba-p/13581118" target="_blank">release 2308</A>, we can go one step further and create a new custom RAP event from an SAP standard event. This event type is called <STRONG>Derived Event</STRONG> and is immensely popular among our customers.<BR />For those who are new in the topic, please follow the blog series introduced in SAP Community<SPAN> </SPAN><A href="https://pages.community.sap.com/topics/abap-connectivity" target="_self" rel="noopener noreferrer">ABAP Connectivity</A><SPAN> page under </SPAN><SPAN>Enterprise Event Enablement feature content to learn how to produce and consume RAP business events and get more details in regard to it.</SPAN></P><P>Under SAP Business Accelerator Hub, you can find all available Event Objects. However, only those events developed as an extendable cloud object can be maintained. To find them out, in <A href="https://api.sap.com/products/SAPS4HANACloud/onstackextensibility/bointerface" target="_blank" rel="noopener noreferrer">SAP Business Accelerator Hub </A>- On Stack Extensibility in Business Object Interface area, look your topic of interest, let us say ‘Sales Order’</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de1.png" style="width: 603px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197895iE1FD425A913DC3C2/image-dimensions/603x509?v=v2" width="603" height="509" role="button" title="de1.png" alt="de1.png" /></span></P><P>Here, in General Information Section, you will find the name of the Extensible Interface BO:<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de2.jpg" style="width: 708px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197896i962B3ADD747CCC83/image-dimensions/708x570?v=v2" width="708" height="570" role="button" title="de2.jpg" alt="de2.jpg" /></span></P><H2 id="toc-hId-1076652628"><STRONG>Find the extensible RAP BO </STRONG></H2><P>For developer extensibility, you need to extend the underlying RAP BO <STRONG>R_SalesOrderTP</STRONG> to trigger a custom event when the SAP-defined event is raised.</P><P>The new custom events that are added there, will be published and thus consumable through the published interface. This is the same approach like when adding additional determinations or validations to an extensible RAP business object.</P><P>The underlying RAP BO will have typically the same name only starting with an “R_” instead of “I_” as the interface listed in the Business Accelerator Hub. So “R_SalesOrderTP” instead of “I_SalesOrderTP”.</P><P>Unfortunately the SAP Business Accelerator Hub does only show the interface <STRONG>I_SalesOrderTP</STRONG> because it focuses on Key User Extensibility so far. As mentioned above, we however need to extend the underlying <STRONG>R_SalesOrderTP</STRONG> object. To find the extensible R_-object we describe in the following several options: </P><UL><LI>To find the suitable Behavior Definition, click on ‘Browse’ option and enter search string similar to the interface name, i.e. *salesordertp*, then from the matching item, choose the Behavior Definition.</LI></UL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de5.jpg" style="width: 595px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197905i77B4B0EB037663E5/image-size/large?v=v2&px=999" role="button" title="de5.jpg" alt="de5.jpg" /></span></P><UL><LI> Alternatively, if you simply give the interface name in the Behavior Definition section, the system shows an error message and suggest the name of the suitable Behavior Definition.</LI></UL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de6.jpg" style="width: 550px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197907i5DB8F2F1273638F6/image-size/large?v=v2&px=999" role="button" title="de6.jpg" alt="de6.jpg" /></span></P><UL><LI>In ADT, you can also open the ABAP Development Object and look for the SAP Object type, in our case ‘SALESORDER.’ Then in the ‘Relation Explorer’ you can find all the related objects to this object type.</LI></UL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="d7.jpg" style="width: 564px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198264i597273D7ACF34465/image-size/large?v=v2&px=999" role="button" title="d7.jpg" alt="d7.jpg" /></span></P><UL><LI>Yet another alternative would be to open the interface and use <STRONG>CTRL+ mouse</STRONG> click over the interface name in the source code and navigate to the Base Behavior.</LI></UL><H2 id="toc-hId-880139123"><STRONG>Define a Derived Event</STRONG></H2><P>To start with, <SPAN>create the </SPAN><STRONG>Released Objects</STRONG><SPAN> view on the repository of your system in your ADT Project as it is explained in my <A href="https://community.sap.com/t5/technology-blogs-by-sap/add-custom-context-attributes-for-sap-released-event-types/ba-p/13940929" target="_self">previous blog post</A>.</SPAN><BR />In Project Explorer, extend your S/4 HANA cloud system, then under ‘Released Objects, EXTENDED_IN_CLOUD_DEVELOPMENT’ section, choose ‘Core Data Services, Behavior Definitions’, open the underlying RAP BO <STRONG>R_SalesOrderTP</STRONG> of the interface you found in the previous section in which the events are defined. <BR /><SPAN>As you can see, this RAP BO is extensible and contains three kinds of events. Besides, the event referenced by the derived event needs to be exposed in the C0 and C1 released </SPAN><SPAN>RAP</SPAN><SPAN> BO interface, also the CDS view entity which serves as the data source for the payload of the derived event needs to be C1 released. More can be found SAP Help Portal, on </SPAN><A href="https://help.sap.com/docs/abap-cloud/abap-rap/derived-business-events" target="_blank" rel="noopener noreferrer">Derived Business Events</A><SPAN>.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="picture blog 1.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199832i7B81A62FD6EEEEE9/image-size/large?v=v2&px=999" role="button" title="picture blog 1.png" alt="picture blog 1.png" /></span></P><P>To extend this RAP BO, on the left-hand side, right click on the name <STRONG>R_SalesOrderTP</STRONG> and choose ‘New Behavior Extension’ option. Choose your package and give a name and description for this behavior extension. <BR />You have to enter the name of the interface <STRONG>I_SALESORDERTP</STRONG> in the field BO Interface. The name of the Behavior definition <STRONG>R_SalesOrderTP</STRONG> will be added automatically.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="picture blog 2.png" style="width: 691px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199835i428DFE2B13991412/image-size/large?v=v2&px=999" role="button" title="picture blog 2.png" alt="picture blog 2.png" /></span></P><P>Click on ‘Next’, choose your transport and click on ‘Finish’. Your behaviour extension is created. Since our extension concerns a minimal change in the payload, we do not need to do much coding like adding a class as such. So, simply replace the generated code with the following lines:</P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>extension using interface i_salesordertp;
extend behavior for salesorder
{
managed event zzSGBEvntCreated on created parameter ZR_CUSTOMSALESORDER;
}</code></pre><P> </P><P> </P><P>Our aim is to extend the SAP event ‘Created’. The keyword for defining the Derived Event is ‘managed’ as a Derived Event is a managed event. Then, we define this new event by giving a name for it. This event name must be started with either 'zz' or 'yy'. Then you need to provide a view entity as a parameter in which the Derived Event will be defined and contains the payload you want. It would be better to define this CDS view in advance, but you can add it here as well.</P><P>Technically speaking, the Derived Event is a new event, the so <SPAN>called ‘old’</SPAN> standard event stays as it was defined originally. In another word, although we are speaking of an extension, with Derived Event we are just cloning that original event in a sense that we DO NOT change the payload of the original one, all changes are done in the new Derived Event payload. In this case, whenever an SAP event is generated, a Derived Event will be triggered automatically.</P><P>It is essential to consider that the CDS view which defines the Derived Event payload must have the same key fields as the root view in the BDEF. Besides, there should not be any associations defined in this view entity. Here, we select the fields from the I-view. However, you can technically use any view which has the same keys.</P><P>As an example, we would like to have the following fields in the payload whenever the total net amount is more than a specific number. So, we define the view as</P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>define view entity ZR_CUSTOMSALESORDER
as select from I_SalesOrder
{
key SalesOrder,
TransactionCurrency,
@Semantics.amount.currencyCode:TransactionCurrency'
TotalNetAmount
} where TotalNetAmount > 9999</code></pre><P> </P><P> </P><P>Using where phrase, you can set a condition acting like a filter. For example, this event will be triggered whenever the Total Net Amount is equal or more than 10000. In this case, the query on the CDS view is executed and if no data is returned due to the WHERE-condition, no event is triggered. Note that in case of a deletion, there is no record left in the table and no derived event can be raised. Hence, be careful when creating derived events on deletions.</P><P>Until now, we create a new event which works like any other standard events. This means, to use this event we need to create the event binding and then configure the channel binding.</P><H2 id="toc-hId-683625618"><STRONG>Create the Event Binding</STRONG></H2><P>Now we design our custom event, and we like to expose it to the consumer world. Following the standard procedure, the next step is mapping this event to the external event infrastructure by creating an event binding. This concept is already explained in <A href="https://community.sap.com/t5/technology-blogs-by-sap/how-to-create-rap-business-events-in-sap-btp-abap-environment/ba-p/13546199" target="_blank">Creating RAP Business Events</A> blog post. The event binding belongs to the design time, here you define how should your event type look like i.e. with which topic name you want to expose it. Add the <A href="https://help.sap.com/docs/abap-cloud/abap-development-tools-user-guide/creating-event-bindings?q=event%2520binding" target="_blank" rel="noopener noreferrer">event binding</A> exactly like it explains for a RAP event. After filling out the ‘General Information’ section, click on ‘Add’ option and provide with the entity name and the event name. Here, the entity name is the name of the extensible interface, and the entity event name is the name you already choose for your Derived Event.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de8.jpg" style="width: 688px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198265iEF099DE4419DCC6E/image-size/large?v=v2&px=999" role="button" title="de8.jpg" alt="de8.jpg" /></span></P><P>Now save and activate the event binding. As we are finishing with the design time, we need to continue with the configuration time to be able to consume this event.</P><H2 id="toc-hId-487112113"><STRONG>Derived Event Configuration </STRONG></H2><P>As a next step and similar to an standard event configuration, we need to create a channel and configure the channel binding. In the consumer system, create a communication arrangement as it explains in SAP help page on <A href="https://help.sap.com/docs/SAP_S4HANA_CLOUD/6ef7f849fed34f95adfc449f29835255/b8410b08bc8b42fe977cca2db018260d.html?q=create+communication+arrangemenet+for+event+enablement" target="_blank" rel="noopener noreferrer">Creating Communication Arrangement</A>. It is also discussed in <A href="https://community.sap.com/t5/technology-blogs-by-sap/how-to-create-rap-business-events-in-sap-btp-abap-environment/ba-p/13546199" target="_blank">creating RAP Business Events</A> blog post.<BR />By creating the communication arrangement, a channel will be created respectively. You can also use any existing active channel if you want. Now, we need to add the event topic to the outbound channel. This is done by the outbound configuration. After selecting your channel in ‘Maintain Event Channel Binding’ application, click on ‘create’ and find the topic which is generated during the event binding creation.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de9.jpg" style="width: 771px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198267i91A1416B31A888BA/image-size/large?v=v2&px=999" role="button" title="de9.jpg" alt="de9.jpg" /></span></P><P>Click on ‘Create’, the topic will be added to the outbound topic bindings of the channel:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de10.jpg" style="width: 849px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198268iA895B74A9F1937D1/image-size/large?v=v2&px=999" role="button" title="de10.jpg" alt="de10.jpg" /></span></P><P>As said, whenever an standard event is triggered, a Derived Event will also be triggered accordingly. In our case, this means after creating a new sales order.</P><P>Then, open ‘Enterprise Event Enablement-Event Monitor’ application, choose your channel and check the event payload, as it can be seen, the fields we were interested in, are added to the payload:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="de11.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198270i6E86DD64FE1FC62C/image-size/large?v=v2&px=999" role="button" title="de11.png" alt="de11.png" /></span></P><H2 id="toc-hId-290598608"><STRONG>Summary </STRONG></H2><P>In this blog post I explained how one can create a RAP custom event based on an SAP standard event type. This new event is raised with the corresponding SAP released event. We also see that by means of a ‘Where’ condition, we can set a limitation for triggered custom events, i.e. if the SELECT does not return any data, the derived event will not be triggered/send.</P><P>In the next post, I would like to show you how you can do source filtering of events and defining filterable properties. I will also introduce dynamic topics and explain how one can use them for routing and filtering in SAP Integration Suite, Advanced Event Mesh (AEM). So, please stay connected!</P>2024-12-04T11:42:10.468000+01:00https://community.sap.com/t5/technology-blogs-by-members/s-4-hana-cloudification-guide-for-developer-navigating-to-released-apis/ba-p/13950875S/4 HANA Cloudification Guide for Developer: Navigating to Released APIs from Classic Objects2024-12-05T15:57:16.495000+01:00aoyanghttps://community.sap.com/t5/user/viewprofilepage/user-id/14700<P><STRONG><FONT size="5">Introduction</FONT></STRONG></P><P>This blog aims to provide a simple guide for discovering newly released APIs that replace traditional SAP objects, including tables, function modules, class objects, and more.</P><P>Whether your organization is implementing Clean Core mindset in S4/HANA On-remise or going through cloud migration(SAP RISE Private Cloud/Public Cloud), one of the first steps towards cloudification is to assess the existing custom solutions are <SPAN>clean core compatible. </SPAN></P><P>The <A href="https://learning.sap.com/learning-journeys/practicing-clean-core-extensibility-for-sap-s-4hana-cloud/explaining-extensibility-model-best-practices_e290f382-800e-40ef-a203-85a13115f487" target="_blank" rel="noopener noreferrer">3-tier extensibility model</A> is a classification that provides rough idea of how much risk of system upgrade will disrupt your custom solution and how protected and stable it is. In the prerequisite of Tier 1, which by definition has the smallest risk of getting affected by upgrade disruption, states the enforced usage of released APIs. Using released objects is a must and a first step towards clean core way of building custom solutions in your SAP system. </P><P><STRONG>The challenge with deprecated objects</STRONG></P><P>Before this clean core concept or 3-tier extension model were introduced, the standard way to extend SAP ERP core is using now so-called classic extensibility, which corresponds to the 3rd-tier in the 3tier-extensibility model. Organizations operating with SAP before this new concept are most likely full of classic extensibility solution. If their system is rated with today's clean core standard, the result will probably say it's not cloud ready/compatible. <U>Number of SAP objects used in the classic solution are now labeled as deprecated in the new standard, resulting in renovating all the custom solution that uses the deprecated objects. To adapt to the new standard, it is <U>crucial to map the deprecated objects to the new released APIs to ensure the functionality and the performance of the custom solutions.</U></U></P><P>(This is, of course, not customer's fault as back then the solutions were probably implemented with the newest technology, insight and standard of that time.)</P><P>With this in mind, let's look at what's the easiest way to find released APIs for each classic ABAP objects.</P><P><STRONG><FONT size="5">1. Classic objects </FONT></STRONG><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span><FONT size="5"><STRONG> Released objects</STRONG> </FONT></P><P><FONT size="5">Database Tables</FONT></P><P>The easiest way is to use Fiori App: View Browser(F2170). Check out <span class="lia-unicode-emoji" title=":right_arrow:">➡️</span> <A href="https://sapextensibility101.com/finding-released-cds-views-for-classic-sap-tables/" target="_blank" rel="noopener nofollow noreferrer">Finding released CDS views for classic SAP tables </A> for detailed steps to find released CDS views for classic SAP tables. </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733236102829.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197968iF9F15F86216AF63A/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733236102829.png" alt="aoyang_0-1733236102829.png" /></span></P><P>The second easiest way is to use SAP Cloudification Repository, which is also covered in the blog above (however not all objects are listed).</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_1-1733152040280.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197487i3ACCAD5C1033E9CF/image-size/large?v=v2&px=999" role="button" title="aoyang_1-1733152040280.png" alt="aoyang_1-1733152040280.png" /></span></P><P><FONT size="5">Function Modules / Class</FONT></P><P>Open the function module in question with ABAP Development Tool(ADT). Open Properties->API State and the successor object is specified.</P><P>Example below checks for function module BAPI_PO_CHANGE and class object CL_SD_DOCUMENT_FLOW_RT.</P><P> <span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_1-1733233148262.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197933iC46126EE23B6C5FF/image-size/large?v=v2&px=999" role="button" title="aoyang_1-1733233148262.png" alt="aoyang_1-1733233148262.png" /></span></P><P> <span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733233054119.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197930i8AEAA5B247D657AF/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733233054119.png" alt="aoyang_0-1733233054119.png" /></span></P><P>Alternatively, you can use SAP Cloudification Repository(however not all objects are listed).</P><H3 id="toc-hId-1205593059"> </H3><P><FONT size="6"><FONT size="5">Business Add-Ins (BAdIs) Definitions</FONT> </FONT></P><P>Open the BAdI Definition in question with ABAP Development Tool(ADT). When opening the object, the enhancement spot that uses the BAdI Definition should open and all the BAdI Definitions will be listed. Right click on the BAdI Definition in question -> API State -> Display Use System-Internally.</P><P>Example below checks for BAdI Definition MEOUT_BAPI_CUST.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733235338721.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197958i9E4CE4133C80BA02/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733235338721.png" alt="aoyang_0-1733235338721.png" /></span></P><P>Release state is shown as well as the successor objects if you click Next.</P><P> <span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_1-1733235515221.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197960iE84D0EE684C07856/image-size/large?v=v2&px=999" role="button" title="aoyang_1-1733235515221.png" alt="aoyang_1-1733235515221.png" /></span></P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733235887038.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197966i112971458A364C9A/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733235887038.png" alt="aoyang_0-1733235887038.png" /></span></P><P> </P><P><FONT size="5">Function Interfaces, Authorization Object, Data Types..etc.</FONT></P><P><FONT size="3">Successor for rest of objects can be found in ADT same way as function module and class objects. </FONT></P><P> </P><P><FONT size="6"><STRONG><FONT size="5">2. Exploring released APIs</FONT></STRONG></FONT></P><P><FONT size="6"><FONT size="5">In ABAP Development Tool(ADT)</FONT></FONT></P><P>ADT offers tree views to list all the objects depending on the object release status. You can also customize the tree as you see fit by adding Application Component, Packages and Software Component as an extra layer. It does not only show the released objects but also deprecated objects as well as deprecated objects with successors. </P><P>Check out <span class="lia-unicode-emoji" title=":right_arrow:">➡️</span> <A href="https://sapextensibility101.com/exploring-released-apis-in-abap-development-tool/" target="_blank" rel="noopener nofollow noreferrer">Exploring released APIs in ABAP Development Tool</A> for step-by-step guide. </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733407294572.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198802i2C75239EB0859A44/image-size/medium?v=v2&px=400" role="button" title="aoyang_0-1733407294572.png" alt="aoyang_0-1733407294572.png" /></span></P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733398787981.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198724iCAB4D77089FC24CF/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733398787981.png" alt="aoyang_0-1733398787981.png" /></span></P><P> </P><P>Trees that show Released Objects, Deprecated Objects and Deprecated Objects with Successors</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_1-1733407699573.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198804i7C48EFCDB6D62FD1/image-size/medium?v=v2&px=400" role="button" title="aoyang_1-1733407699573.png" alt="aoyang_1-1733407699573.png" /></span></P><P> </P><P><FONT size="6"><FONT size="5">In SAP Accelerator Hub</FONT></FONT></P><P><A href="https://api.sap.com/" target="_self" rel="noopener noreferrer">SAP Accelerator Hub</A> is an alternative to find API's for those that don't have developer access and want to explore APIs from business context. It contains not just APIs for tier1/tier2 cloud development, but also out-of-box template for business processes, integration scenarios, events based solutions and everything you need for extension your SAP ERP system. Choose your product(S/4 Public/Private Edition, BTP, etc) and start exploring.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733408880756.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198822i7F0124AF4A0E594F/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733408880756.png" alt="aoyang_0-1733408880756.png" /></span></P><P>Filter the package and explore released APIs with your desired business area. </P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733410315213.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/198836i307995027191CED5/image-size/large?v=v2&px=999" role="button" title="aoyang_0-1733410315213.png" alt="aoyang_0-1733410315213.png" /></span></P><P> </P><P><FONT size="6">Appendix</FONT></P><P><STRONG>Released APIs</STRONG></P><P>APIs marked as released are indic<FONT size="3">ation tha</FONT>t they are <SPAN>technically stable and is the only option available in tier 1 extension to communicate with SAP backend. <SPAN>SAP categorizes the released objects in 5 ways depending on the types and the intension of the extension. In this blog, we focus on the cloudification of SAP objects used for custom development hence will only touch on C1 Contract (Use System-Internally).</SPAN></SPAN></P><UL><LI><FONT size="2"><SPAN>Extend (C0)</SPAN></FONT></LI><LI><FONT color="#FF6600"><STRONG><FONT size="2">Use System-Internally (C1)</FONT></STRONG></FONT></LI><LI><FONT size="2"><SPAN>Use as Remote API (C2)</SPAN></FONT></LI><LI><FONT size="2"><SPAN>Manage Configuration Content (C3)</SPAN></FONT></LI><LI><SPAN><SPAN><FONT size="2">Use in ABAP-Managed Database Procedures (C4)</FONT></SPAN></SPAN></LI></UL><P><STRONG><FONT size="3">C1 Contract (Use System-Internally)</FONT></STRONG></P><P><FONT size="3">Released in C1 contracts indicate that the object is stable enough to be used in Key-User Extension(Custom fields and Custom Logic apps) and Developer Extensibility(custom solution developed solely by ABAP Development for Cloud language scope). The release state is managed separately for each usage and can be found in ABAP Development Tool.</FONT></P><P><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="aoyang_0-1733151446442.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/197484i5748457DEDFD2719/image-size/medium?v=v2&px=400" role="button" title="aoyang_0-1733151446442.png" alt="aoyang_0-1733151446442.png" /></span></P><P> </P>2024-12-05T15:57:16.495000+01:00https://community.sap.com/t5/technology-blogs-by-sap/one-tool-to-track-them-all/ba-p/13957191One Tool to Track Them All2024-12-06T15:21:19.467000+01:00bernd_schmitthttps://community.sap.com/t5/user/viewprofilepage/user-id/197557<P><SPAN>We launched our process-tracking tool, <A href="https://community.sap.com/t5/technology-blogs-by-sap/process-observer/ba-p/13355424" target="_blank"><STRONG>Process Observer</STRONG></A>, over a decade ago. Since then, a lot has changed. Now, our goal is Cloud First, and we want our customers to <STRONG>RISE</STRONG> to the cloud and <STRONG>GROW</STRONG> in the cloud.</SPAN></P><P>SAP acquired and integrated <SPAN><A href="https://www.signavio.com/" target="_blank" rel="noopener nofollow noreferrer">Signavio</A></SPAN> a while ago and our biggest question was - what is the future of Process Observer in the cloud and how does it play together with <SPAN><A href="https://www.signavio.com/products/process-intelligence/" target="_blank" rel="noopener nofollow noreferrer">SAP Signavio Process Intelligence</A></SPAN>? The answer <EM>— </EM>A new kid on the block, "BUSINESS EVENT LOGGING (BEL)."</P><P><STRONG>BEL</STRONG> uses a much leaner and more performant approach compared to <STRONG>Process Observer</STRONG>. It also requires less configuration on your part while still giving you the freedom to enhance and integrate your processes. At the same time, it allows you to easily integrate with <STRONG>SAP Signavio Process Intelligence</STRONG>.</P><P> </P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bernd_schmitt_0-1733483902072.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199144i9E8976ACAC0E1FF2/image-size/large?v=v2&px=999" role="button" title="bernd_schmitt_0-1733483902072.png" alt="bernd_schmitt_0-1733483902072.png" /></span></P><P style=" text-align: center; "><SPAN> Fig. 1: <STRONG>Event Log Viewer App in Business Event Logging</STRONG></SPAN></P><P> </P><P><STRONG>Overview and Benefits</STRONG></P><P>So, what is Business Event Logging?</P><UL><LI> It collects the event data locally and you can use integration to extract the data into <STRONG>SAP Signavio Process Intelligence</STRONG>.</LI><LI>It is based on <SPAN><A href="https://community.sap.com/t5/technology-blogs-by-sap/introducing-rap-business-events/ba-p/13565543" target="_blank">Business Events</A></SPAN>, but it is also planned to support other sources like Change Documents.</LI><LI>It provides field change information.</LI><LI>It is available now in SAP S/4HANA CE, SAP S/4HANA OP/PC and SAP ABAP Platform Cloud.</LI></UL><P>How can BEL be useful for you?<SPAN><BR /></SPAN></P><UL><LI>You can activate logging of events just by selecting the relevant Object Types. You can create process views (“cases”) in <STRONG>SAP Signavio Process Intelligence</STRONG> and analyze your processes there.</LI><LI>You can use the data viewer apps to review logged data in multiple aspects.</LI><LI>You can manage the data retention in the business event log with SAP ILM.</LI><LI>You can extend processes or log your own processes by creating your own Business Events.</LI></UL><P> </P><P><STRONG>The Foundation</STRONG></P><P>Business events are object-centric events created in the RAP framework. They are assigned with an event binding and are C2-released by SAP. You can find these events documented in the <SPAN><A href="https://hub.sap.com/products/SAPS4HANACloud/events/events" target="_blank" rel="noopener noreferrer">SAP Business Accelerator Hub</A></SPAN>, Follow the path: <EM>Explore / <your product> / Events</EM>. </P><P> </P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="bernd_schmitt_1-1733483980105.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199145iBAD653F59DEC2CE4/image-size/large?v=v2&px=999" role="button" title="bernd_schmitt_1-1733483980105.png" alt="bernd_schmitt_1-1733483980105.png" /></span></P><P style=" text-align: center; "><SPAN>Fig. 2: <STRONG>Business Events in the BEL Accelerator Hub</STRONG></SPAN></P><P>The RAP framework is an extensible framework: you can create your own objects, create events with binding, extend SAP delivered objects with your events, or just extend an SAP-delivered event.</P><P>Business events can also contain change information. For more information, you can explore event definitions in the SAP Business Accelerator Hub. This change information is now visible in the BEL log.</P><P>If you require additional standard events delivered by SAP, or change information, you can raise a request via the <SPAN><A href="https://influence.sap.com/sap/ino/#/campaign/1175" target="_blank" rel="noopener noreferrer">Customer Influence Portal</A></SPAN>. .</P><P>Beyond these Business Events, there are internal events such as RAP events, SAP-delivered C1- events, and Change Documents for other BEL data sources. We plan to support them in the future and will keep you updated.</P><P> </P><P><STRONG>Release support</STRONG></P><P>You might be wondering when you could start using this. The great news is that if you’re in the cloud you can start right away!</P><P><U><STRONG>SAP S/4HANA Public Cloud & SAP BTP, ABAP Environment:</STRONG></U></P><P>For the <STRONG>SAP S/4HANA Cloud Public Edition </STRONG><STRONG>2408</STRONG><STRONG> or later</STRONG> and for <STRONG>SAP BTP, ABAP Environment 2411</STRONG> or later, we support:</P><UL><LI>Logging of all released business events for all object types as listed in the SAP Accelerator Hub for the product.</LI><LI>Logging of customer events. For more information, see the instructions in the product documentation.</LI></UL><P>You can find the detailed documentation for Business Event Logging for these products here:</P><P>SAP S/4HANA Cloud Public Edition (latest): <SPAN><A href="https://help.sap.com/docs/SAP_S4HANA_CLOUD/a630d57fc5004c6383e7a81efee7a8bb/cee09744c9584649ac1d6d05473c6e56.html" target="_blank" rel="noopener noreferrer">User documentation</A></SPAN> </P><P>SAP BTP, ABAP Environment (latest): <SPAN><A href="https://help.sap.com/docs/sap-btp-abap-environment/abap-environment/business-event-logging" target="_blank" rel="noopener noreferrer">User documentation</A></SPAN> </P><P><U><STRONG>SAP S/4HANA Private Cloud & On-Premise:</STRONG></U></P><P>The support in the <STRONG>SAP S/4HANA Private Cloud </STRONG><STRONG>Edition and On-Premise Edition </STRONG>depends on the release.</P><P>Functionalities provided with PC/OP 2021 FPS2: </P><UL><LI>Only logging of Order-to-Cash related events provided by SAP (based on <SPAN><A href="https://community.sap.com/t5/enterprise-resource-planning-blogs-by-sap/sap-business-objects-business-event-handling/ba-p/13394011" target="_blank">Business Event Handling</A></SPAN>). </LI><LI>Customer extensibility is not supported by Business Event Handling.</LI></UL><P>Functionalities provided with PC/OP 2022 FPS1: </P><UL><LI>Only logging of Order-to-Cash related events provided by SAP (based on <SPAN><A href="https://community.sap.com/t5/technology-blogs-by-sap/introducing-rap-business-events/ba-p/13565543" target="_blank">RAP</A></SPAN>) </LI><LI>Customer events are supported with FPS 2 of OP 2022</LI></UL><P>Functionalities provided with PC/OP 2023 FPS2: </P><UL><LI>Logging of all Business Events provided by SAP is supported (as documented in the SAP Business Accelerator Hub).</LI></UL><P>Functionalities provided with S/4HANA Private Cloud / On Premise 2023 (latest):</P><UL><LI>You can view the list of functionalities in the <SPAN><A href="https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/8308e6d301d54584a33cd04a9861bc52/cee09744c9584649ac1d6d05473c6e56.html" target="_blank" rel="noopener noreferrer">User documentation</A></SPAN>.</LI></UL><P>We will cover the integration of the component and the customer extensibility in separate articles:</P><UL><LI><A href="https://community.sap.com/t5/technology-blogs-by-sap/using-customer-defined-events-in-business-event-logging/ba-p/13982568" target="_blank">Using Customer-Defined Events in Business Event Logging</A></LI></UL>2024-12-06T15:21:19.467000+01:00https://community.sap.com/t5/technology-blogs-by-members/building-a-rap-application-from-custom-actions-to-sending-emails-a-step-by/ba-p/13958287Building a RAP Application: From Custom Actions to Sending Emails – A Step-by-Step Guide2024-12-08T23:37:14.397000+01:00ertugrul_bagcihttps://community.sap.com/t5/user/viewprofilepage/user-id/775459<P>If you've started exploring SAP RAP, you may have noticed that classes like <STRONG>CL_BCS</STRONG>, which are typically used for sending emails in SAP, cannot be directly used in RAP. The main reason is that RAP does not allow the use of "COMMIT" which is required by these classes.</P><P>In this blog, I aim to address this limitation while also exploring how to create a custom action and build a simple RAP project.</P><P>The blog will be structured around the following key topics:</P><OL><LI>Creation of Interface and Consumption CDS Views</LI><LI>Creation of Metadata</LI><LI>Creation of the Service</LI><LI>Creation of Behavior</LI><LI>Creation of Class and Action</LI><LI>Email Sending Process</LI></OL><P>To ensure clarity, we will proceed with an example scenario throughout the blog. Our scenario involves listing invoices and some details from the <STRONG>VBAK</STRONG> table, and sending the selected data via email as part of the email sending process.</P><P><FONT size="6">Creation of Interface and Consumption CDS Views</FONT></P><P>Interface CDS is used to abstract raw data into a reusable and meaningful structure, serving as the foundational data model. Consumption CDS, on the other hand, processes this data to make it user-friendly and tailored for specific use cases, such as reporting, Fiori UI, or analytical solutions.</P><P>Even though we might not need it for this project, it is generally good practice to follow this structure. Let's start by creating the Interface CDS view.</P><P>For the sake of example, I have added a few fields. You can expand it according to your scenario. Additionally, ensure that the entity is marked as "root," as this will be our top-level entity. [Figure-1]</P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="ertugrul_bagci_0-1733693647522.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199705i5087A809D5F94E04/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_0-1733693647522.png" alt="ertugrul_bagci_0-1733693647522.png" /></span><FONT size="2">Figure-1</FONT></P><P style=" text-align : left; "> During the creation of the Consumption CDS, we used the "Audat" filter to narrow down our dataset and also to leverage the Consumption logic. [Figure-2]</P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_1-1733694057130.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199706i317D14CB0E81CC28/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_1-1733694057130.png" alt="ertugrul_bagci_1-1733694057130.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-2</FONT></P><P style=" text-align : left; "><FONT size="6">Creation of Metadata</FONT></P><P>In SAP RAP (Restful ABAP Programming Model), <STRONG>metadata extensions</STRONG> are used to enhance the metadata of existing CDS views or entities without modifying the original CDS definition. This is especially useful for tailoring application behavior or UI representations in a decoupled and non-intrusive manner.</P><P>We create metadata from our Consumption CDS.[Figure-3]</P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_1-1733694550358.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199708i0D3A26A3AD0FDFD6/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_1-1733694550358.png" alt="ertugrul_bagci_1-1733694550358.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-3</FONT></P><P style=" text-align : left; "><FONT size="4">After creating the metadata extensions, we add annotations.[Figure-4] </FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_2-1733694616782.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199709i1CF2FFB5208AB289/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_2-1733694616782.png" alt="ertugrul_bagci_2-1733694616782.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-4</FONT></P><P style=" text-align : left; "><FONT size="6">Creation of the Service</FONT></P><P>Now, we create a service definition from our Consumption CDS.<BR />You can follow Figures 5 and 6 for reference.</P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_4-1733694729771.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199711i7116383582B6AF14/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_4-1733694729771.png" alt="ertugrul_bagci_4-1733694729771.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-5</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_5-1733694749408.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199712iDE9D78638DBED47C/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_5-1733694749408.png" alt="ertugrul_bagci_5-1733694749408.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-6</FONT></P><P style=" text-align : left; ">After the service is created, we must not forget to<STRONG> expose</STRONG> our Consumption CDS views.<FONT size="4">[Figure-7]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_7-1733694864062.png" style="width: 497px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199714i23B4B0DB27913B00/image-dimensions/497x113?v=v2" width="497" height="113" role="button" title="ertugrul_bagci_7-1733694864062.png" alt="ertugrul_bagci_7-1733694864062.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-7</FONT></P><P style=" text-align : left; "><FONT size="4">Now, we need to create a service binding. For this, we will use the service definition we previously created.[Figure-8]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_8-1733694951607.png" style="width: 491px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199715iE9827CEADE6BB588/image-dimensions/491x74?v=v2" width="491" height="74" role="button" title="ertugrul_bagci_8-1733694951607.png" alt="ertugrul_bagci_8-1733694951607.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-8</FONT></P><P style=" text-align : left; "><FONT size="4">Make sure to select <STRONG>"OData V2 - UI"</STRONG> as the Binding Type.<BR />When the service is first created, it will not be published. To publish it, click the button I have highlighted.[Figure-9]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_9-1733695053234.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199716i217D86A45B5AD920/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_9-1733695053234.png" alt="ertugrul_bagci_9-1733695053234.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-9</FONT></P><P style=" text-align : left; "><FONT size="4">In the published service, you can view the entity sets and associations that you have added.[Figure-10]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_0-1733695202499.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199717i616E651CFF707850/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_0-1733695202499.png" alt="ertugrul_bagci_0-1733695202499.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-10</FONT></P><P style=" text-align : left; "><FONT size="4"><BR />If you want to test the service, simply double-click on the entity. This allows you to test your service easily.[Figure-11</FONT><FONT size="4">]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_1-1733695208679.png" style="width: 582px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199718i3984E76E811D9D9F/image-dimensions/582x80?v=v2" width="582" height="80" role="button" title="ertugrul_bagci_1-1733695208679.png" alt="ertugrul_bagci_1-1733695208679.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-11</FONT></P><P style=" text-align : left; "><FONT size="6">Creation of Behavior</FONT></P><P style=" text-align : left; "><FONT size="4">Behavior definitions for the business object entities in a given composition model are established for the root CDS view, outlining the behavior for all included entities.</FONT></P><P>Therefore, we create Behavior definitions for both the Interface and Consumption CDS views.</P><P>Let's start with the Interface CDS.<FONT size="4">[Figure-12]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_2-1733695392048.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199719iAE1E4C49FAEBA89E/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_2-1733695392048.png" alt="ertugrul_bagci_2-1733695392048.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-12</FONT></P><P>After creating the Behavior, we add an alias.<BR />Since we will not perform create, update, or delete operations, we can disable these actions. <FONT size="4">[Figure-13]</FONT></P><P>The class <STRONG>"zbp_i_vbak_example"</STRONG> will be created in later steps.</P><P> </P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_3-1733695462434.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199720i096A4FCE5BE1867A/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_3-1733695462434.png" alt="ertugrul_bagci_3-1733695462434.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-13</FONT></P><P> </P><P>Now, we need to create a Behavior for our Consumption CDS.<FONT size="4">[Figure-14 & 15]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_4-1733695539600.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199721i2B6734E9B9DE94AF/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_4-1733695539600.png" alt="ertugrul_bagci_4-1733695539600.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-14</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_6-1733695561696.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199723i1C35E4CD73DD164D/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_6-1733695561696.png" alt="ertugrul_bagci_6-1733695561696.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-15</FONT></P><P style=" text-align : left; "><FONT size="4">We have successfully created the Behavior within the Consumption CDS. Now, we can move on to the next step.</FONT></P><P><FONT size="6">Creation of Class and Action</FONT></P><P><FONT size="4">To make the action we are going to create functional, we need a class.<BR />To create the class, go to the Behavior, right-click, and select <STRONG>"Quick Fix"</STRONG>.[Figure-16]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_7-1733695765262.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199724iAF8DF996F00EE116/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_7-1733695765262.png" alt="ertugrul_bagci_7-1733695765262.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-16</FONT></P><P style=" text-align : left; "><FONT size="4">Here, we select <STRONG>"Create"</STRONG> to create our class.[Figure-17]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_8-1733695860621.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199725iE75941EB444FC2C8/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_8-1733695860621.png" alt="ertugrul_bagci_8-1733695860621.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-17</FONT></P><P> </P><P style=" text-align : left; "><FONT size="4"><BR />The class creation process is now complete.<BR />Make sure to note that all the code we have written is under <STRONG>"Local Types"</STRONG>.[Figure-18]</FONT></P><P style=" text-align: center; "> <span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_9-1733695892829.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199726i1A79458664883173/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_9-1733695892829.png" alt="ertugrul_bagci_9-1733695892829.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-18</FONT></P><P style=" text-align : left; "><FONT size="4">To create an action, we first need an abstract CDS. This CDS will define the input parameters for the action.<BR />For this, we create a new <STRONG>Data Definition</STRONG>.<BR /> Here, we will define the input parameter for the email address.[Figure-19]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_10-1733695981340.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199727i1B1695F286C624A1/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_10-1733695981340.png" alt="ertugrul_bagci_10-1733695981340.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-19</FONT></P><P style=" text-align : left; "><FONT size="4">Next, we go to the Interface ZI_** named behavior and define our action. We will provide the Abstract CDS as the parameter. [Figure-20]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_13-1733696187612.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199730i0B14531D54328F71/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_13-1733696187612.png" alt="ertugrul_bagci_13-1733696187612.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-20</FONT></P><P style=" text-align : left; "><FONT size="4">Then, by clicking the <STRONG>Quick Fix</STRONG> button, we ensure the class method for the action is defined.[Figure-21]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_14-1733696244429.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199731i2DEFD57959CFA047/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_14-1733696244429.png" alt="ertugrul_bagci_14-1733696244429.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-21</FONT></P><P style=" text-align : left; "><FONT size="4">Next, we go to the <STRONG>ZC_</STRONG>*-named behavior and define the action there as well.[Figure-22]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_15-1733696355871.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199732i9EEFCC742DC9FDE1/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_15-1733696355871.png" alt="ertugrul_bagci_15-1733696355871.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-22</FONT></P><P style=" text-align : left; "><FONT size="4">Finally, to make the button visible on the screen, we go to the <STRONG>Metadata Extension</STRONG> and add the relevant line.[Figure-23]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_16-1733696408857.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199733i30CCD2F50CCEDA0C/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_16-1733696408857.png" alt="ertugrul_bagci_16-1733696408857.png" /></span> </P><P style=" text-align: center; "><FONT size="2">Figure-23</FONT></P><P> </P><P> </P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>: { lineItem: [
{ type: #FOR_ACTION, dataAction: 'SendMail', label: 'Send Mail' } ]} </code></pre><P> </P><P> </P><P> </P><P> </P><P>Once we execute the service again, you will be able to see the button added.<FONT size="4">[Figure-24]</FONT></P><P style=" text-align: center; "> <span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_17-1733696481346.png" style="width: 496px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199734i3A23B0F5E64C93C4/image-dimensions/496x62?v=v2" width="496" height="62" role="button" title="ertugrul_bagci_17-1733696481346.png" alt="ertugrul_bagci_17-1733696481346.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-24</FONT></P><P><FONT size="6">Email Sending Process</FONT></P><P>As we mentioned earlier, we cannot use classes like <STRONG>CL_BCS</STRONG> that include a <STRONG>"commit"</STRONG> in RAP for email sending. Therefore, we will use the <STRONG>CL_BCS_MAIL_MESSAGE</STRONG> class to send emails.</P><P>For this, we go to the class where we defined the <STRONG>Send_mail</STRONG> method.<BR />The selected row and email information will be contained in the <STRONG>"keys"</STRONG> variable. We will read the table and send the email. I have not included many details in the email content, but you can add more as needed.<FONT size="4">[Figure-25]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_18-1733696619664.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199735i1CF2D7670E44B840/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_18-1733696619664.png" alt="ertugrul_bagci_18-1733696619664.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-25</FONT></P><P> </P><P> </P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code> METHOD SendMail.
DATA:lv_mail TYPE bcs_msg_sender.
DATA(ls_keys) = VALUE #( keys[ 1 ] OPTIONAL ).
lv_mail = ls_keys-%param-Mail.
DATA(mail) = cl_bcs_mail_message=>create_instance( ).
mail->set_sender( 'Sender@mail.com' ).
mail->add_recipient( lv_mail ).
mail->set_subject( 'Test' ).
mail->set_main( cl_bcs_mail_textpart=>create_instance(
iv_content = '<h2>Hi</h2><p>Hi you can see the details of invoice number ' && ls_keys-Vbeln &&' below. </p>'
iv_content_type = 'text/html' ) ).
mail->send( IMPORTING et_status = DATA(lt_status) ).
ENDMETHOD.</code></pre><P> </P><P> </P><P> </P><P> </P><P> </P><P>Now, we run a preview of the service. We select an invoice, click the <STRONG>Send Mail</STRONG> button, and enter the email address.<FONT size="4">[Figure-26]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_19-1733696746091.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199736i70661F832F683958/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_19-1733696746091.png" alt="ertugrul_bagci_19-1733696746091.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-26</FONT></P><P style=" text-align : left; "><FONT size="4">To check the email, we will use the <STRONG>"SOST"</STRONG> transaction code.<BR />As shown in the figure, the email has been successfully sent.[Figure-27]</FONT></P><P style=" text-align: center; "><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ertugrul_bagci_20-1733696789414.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/199737iC591146B12EB6244/image-size/medium?v=v2&px=400" role="button" title="ertugrul_bagci_20-1733696789414.png" alt="ertugrul_bagci_20-1733696789414.png" /></span></P><P style=" text-align: center; "><FONT size="2">Figure-27</FONT></P><P>I hope it has been a useful blog.<BR />Regards.</P>2024-12-08T23:37:14.397000+01:00https://community.sap.com/t5/technology-blogs-by-members/how-to-call-rap-actions-with-table-types-from-a-list-report/ba-p/13969836How to Call RAP Actions with Table Types from a List Report2024-12-24T22:09:03.542000+01:00MioYasutakehttps://community.sap.com/t5/user/viewprofilepage/user-id/789<H2 id="toc-hId-1077701857">Introduction</H2><P>In this blog, we’ll explore how to define an action in the ABAP RESTful Application Programming Model (RAP) that accepts a <STRONG>table-type parameter</STRONG> and returns <STRONG>a single result</STRONG>. Additionally, we’ll walk through how to integrate this action into a List Report.</P><P>The motivation for exploring this approach came from a requirement to generate a PDF report based on the data from multiple selected rows. While the standard actions in a List Report allow for returning a single result using <EM>"invocationGrouping": #CHANGE_SET</EM>, we, as developers, cannot easily handle such results within custom logic. This led to the idea of creating a custom action.</P><P>For this blog, we’ll demonstrate the implementation using a simpler scenario, focusing on how to realize this functionality step by step.</P><H2 id="toc-hId-881188352">Scenario Overview</H2><P>We will create a simple application focused on calculating inventory values for products. In a List Report, users can select one or more products from the list and trigger the action via a button. The total value will then be displayed in a popup dialog.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_6-1734987501916.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204796iFDF28E3579B1799F/image-size/large?v=v2&px=999" role="button" title="MioYasutake_6-1734987501916.png" alt="MioYasutake_6-1734987501916.png" /></span></P><H2 id="toc-hId-684674847">Development Environment</H2><UL><LI><STRONG>Backend: </STRONG>BTP ABAP Environment (trial)</LI><LI><STRONG><STRONG><STRONG>Frontend: </STRONG></STRONG></STRONG>SAP Business Application Studio</LI></UL><H2 id="toc-hId-488161342">Development Steps</H2><UL><LI><P><STRONG>Backend</STRONG></P><UL><LI>Table Definition</LI><LI>Defining an Action to Handle Deep Parameters</LI><LI>Implement Behavior Logic</LI></UL></LI><LI><STRONG>Frontend</STRONG><UL><LI>Creating a Fiori Elements Application</LI><LI>Implementing the Custom Action</LI></UL></LI></UL><H2 id="toc-hId-291647837"><STRONG>Backend</STRONG></H2><P><STRONG>1. Table Definition</STRONG></P><P>Define a simple table containing product information. </P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Product Stock'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zyasu_stock {
key client : abap.clnt not null;
key id : sysuuid_x16 not null;
product_id : abap.char(20);
price : abap.int2;
stock : abap.int2;
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> </P><P>After creating the table, generate a RAP BO and an OData service using the "Generate ABAP Repository Objects" wizard.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_0-1734900075917.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204330iDE8E04B6F386C5FC/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_0-1734900075917.png" alt="MioYasutake_0-1734900075917.png" /></span></P><P><STRONG>2. Defining an Action to Handle Deep Parameters</STRONG></P><P>An action <SPAN><EM>calcStockAmountDeep</EM> has been added to the auto-generated behavior definition. This action receives a deep parameter, <EM>ZA_PRODUCT_ROOT</EM>.</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>static action calcStockAmountDeep deep parameter ZA_PRODUCT_ROOT result [1] ZA_AMOUNT; </code></pre><P> </P><P>Initially, I was going to use the <STRONG>deep table parameter</STRONG> because my requirement was to pass a single level table entity. However, as posted in <A href="https://community.sap.com/t5/technology-q-a/rap-error-for-action-with-deep-table-parameter-metadata-and-service-binding/qaq-p/12807334" target="_self">this Q&A</A>, this statement does not seem to be supported yet, so I used the deep parameter instead.</P><P><SPAN>To define an action parameter that takes a deep structure as input, the following objects will be created:</SPAN></P><P><STRONG>Root Abstract Entity</STRONG></P><P>This entity contains a table of products. A "dummy" is defined because at least one property must be present in the root entity.</P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Deep Parameter Root'
define root abstract entity ZA_PRODUCT_ROOT
{
dummy: abap.char(1);
_product : composition [0..*] of ZA_PRODUCT_TABLE;
}</code></pre><P> </P><P><STRONG>Child Abstract Entity</STRONG></P><P>This entity contains the key fields of the product entity. An "isActiveEntity" field is added, because the service is draft-enabled. This is necessary if you want to handle both active entities and draft entities in the event handler. </P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Deep Parameter for Products'
define abstract entity ZA_PRODUCT_TABLE
{
productUuId : sysuuid_x16;
isActiveEntity: abap_boolean;
_root: association to parent ZA_PRODUCT_ROOT;
}</code></pre><P> </P><P><STRONG>Abstract Behavior Definition</STRONG></P><P>An abstract behavior definition is required to use the abstract entity as a deep parameter for an action.</P><P> </P><pre class="lia-code-sample language-abap"><code>abstract;
strict ( 2 );
with hierarchy;
define behavior for ZA_PRODUCT_ROOT alias Root
{
association _product;
}
define behavior for ZA_PRODUCT_TABLE alias Product
{
}</code></pre><P> </P><P><STRONG>3. Implement Behavior Logic</STRONG></P><P>First, define the following type in the private section of the behavior handler class. This type will be used to extract the product keys from the parameters passed to the action. </P><P> </P><pre class="lia-code-sample language-abap"><code> TYPES: BEGIN OF ty_key,
id TYPE sysuuid_x16,
is_draft TYPE abp_behv_flag,
END OF ty_key.</code></pre><P> </P><P>Next, implement the <EM>calcStockAmountDeep</EM> method as follows.</P><P> </P><pre class="lia-code-sample language-abap"><code> METHOD calcStockAmountDeep.
DATA amount TYPE i.
DATA lt_productuuid TYPE STANDARD TABLE OF ty_key.
"get product keys
LOOP AT keys INTO DATA(key).
LOOP AT key-%param-_product INTO DATA(product).
APPEND VALUE #( id = product-productUuId
is_draft = SWITCH #( product-isActiveEntity
WHEN abap_true THEN if_abap_behv=>mk-off
ELSE if_abap_behv=>mk-on ) ) TO lt_productuuid.
ENDLOOP.
ENDLOOP.
READ ENTITIES OF zr_yasu_stock IN LOCAL MODE
ENTITY Stock
FIELDS ( Price Stock )
WITH VALUE #( FOR data IN lt_productuuid (
%tky = VALUE #( id = data-id
%is_draft = data-is_draft ) ) )
RESULT DATA(stock_t).
" calculate stock amount
LOOP AT stock_t INTO DATA(stock).
amount = amount + stock-Price * stock-Stock.
ENDLOOP.
" return result
result = VALUE #( FOR key1 IN keys (
%cid = key1-%cid
%param = VALUE #( amount = amount )
) ).
ENDMETHOD.</code></pre><P> </P><P>With the backend implementation complete, we will test the action by calling it from Postman. Before invoking the action, use a GET method to retrieve the CSRF token, and include it in the headers when making the action call. You can confirm that the total stock value is returned successfully.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_2-1734986420942.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204789iB0E245C4F41506F4/image-size/large?v=v2&px=999" role="button" title="MioYasutake_2-1734986420942.png" alt="MioYasutake_2-1734986420942.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_3-1734986455131.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204790iDCD4B9C2EC61295E/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_3-1734986455131.png" alt="MioYasutake_3-1734986455131.png" /></span></P><H2 id="toc-hId-95134332">Frontend</H2><P><STRONG>1. Creating a Fiori Elements Application</STRONG></P><P>In SAP Business Application Studio, select the OData service created in the previous step and use the List Report template to create the application. Since we want to implement the logic using TypeScript, select the "Enable TypeScript" option in the "Project Attributes" during the project setup process.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_7-1734988969774.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204805iE0D23724B3FE7413/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_7-1734988969774.png" alt="MioYasutake_7-1734988969774.png" /></span></P><P><STRONG>2. Implementing the Custom Action</STRONG></P><P>From the Page Map, add an action to the table's toolbar by selecting "<STRONG>Add Custom Action</STRONG>".</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_4-1734986822312.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204791iA5E779B7050BF544/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_4-1734986822312.png" alt="MioYasutake_4-1734986822312.png" /></span></P><P>In the "New Custom Action" dialog, define the action as follows. (Although not visible in the screenshot, the Handler Method was set to <EM>getTotalDeep</EM>.)</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_5-1734987108059.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/204792iAE1D774E5F38526E/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_5-1734987108059.png" alt="MioYasutake_5-1734987108059.png" /></span></P><P>Implement the action in <EM>ext/controller/GetTotalDeep.ts</EM> as follows.</P><P> </P><pre class="lia-code-sample language-javascript"><code>import ExtensionAPI from 'sap/fe/core/ExtensionAPI';
import Context from 'sap/ui/model/odata/v4/Context';
import ListReportExtensionAPI from 'sap/fe/templates/ListReport/ExtensionAPI';
import ODataContextBinding from 'sap/ui/model/odata/v4/ODataContextBinding';
import MessageBox from 'sap/m/MessageBox';
import NumberFormat from 'sap/ui/core/format/NumberFormat';
interface Error {
message: string
error: {
code: string
details: Error[]
}
}
interface Result {
amount: string
}
const namespace = "com.sap.gateway.srvd.zui_yasu_stock_o4.v0001."
/**
* Generated event handler.
*
* this reference to the 'this' that the event handler is bound to.
* pageContext the context of the page on which the event was fired
*/
export function getTotalDeep(this: ExtensionAPI, pageContext: Context) {
//get selected contexts
const ListReportExtensionAPI = this as ListReportExtensionAPI;
const contexts = ListReportExtensionAPI.getSelectedContexts();
const products = contexts.map(context => {
return {
productUuId: context.getProperty("Id"),
isActiveEntity: context.getProperty("IsActiveEntity")
}
})
//invoke the action
const model = ListReportExtensionAPI.getModel();
const operation = model?.bindContext("/Stock/" + namespace + "calcStockAmountDeep(...)") as ODataContextBinding;
operation.setParameter("dummy", "X");
operation.setParameter("_product", products);
const fnSuccess = () => {
//show total
const result = operation.getBoundContext().getObject() as Result;
const amount = result.amount;
const numberFormat = NumberFormat.getIntegerInstance({
groupingEnabled: true
});
var formattedAmount = numberFormat.format(amount);
MessageBox.show(`${formattedAmount} JPY`, {
title: "Stock Amount"
});
}
const fnError = (error:Error) => {
MessageBox.error(error.message);
}
operation.invoke().then(fnSuccess, fnError);
}</code></pre><P> </P><H2 id="toc-hId--101379173">Conclusion</H2><P>In this blog, we explored how to implement a custom action in RAP that processes deep parameters and integrate it with a Fiori Elements List Report. We demonstrated the end-to-end process, from backend implementation to frontend integration.</P><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><DIV class=""><P>Note that in a List Report, clicking "Select All" only selects the rows currently visible on the screen <SPAN>(refer to </SPAN><A href="https://me.sap.com/notes/0002428401" target="_self" rel="noopener noreferrer">SAP Note 2428401</A><SPAN>). As a result, the approach introduced here is best suited for use cases where a few rows from the displayed data are selected, rather than scenarios involving bulk selection of large datasets.</SPAN></P></DIV></DIV></DIV></DIV></DIV></DIV>2024-12-24T22:09:03.542000+01:00https://community.sap.com/t5/technology-blogs-by-members/my-abap-in-eclipse-wish-list-for-2025-enhancements-new-features/ba-p/13972816My ABAP in Eclipse wish list for 2025 enhancements / new features2024-12-27T22:30:05.686000+01:00Timo_Johnhttps://community.sap.com/t5/user/viewprofilepage/user-id/15452<!-- ScriptorStartFragment --><UL><LI><SPAN>"Run in Projekt" Funktion. </SPAN><UL class=""><LI><SPAN>We often develop in client 100 but run / test in client 120. So it would be great if we could set a "run in client" in which Unit Tests / Run / F9 etc are executed. </SPAN><SPAN> So connect 120 as the "run in" client to development client 100.<BR /><BR /></SPAN></LI></UL></LI><LI><SPAN>Allow Comments in RAP Service Definition files.<BR /></SPAN></LI><LI><SPAN>Create Methods using method chains: </SPAN><UL class=""><LI><SPAN>currently </SPAN><SPAN>Z</SPAN><SPAN>CL_Factory=>get_instance( )->createNewMethodWithWizzard() is not supported <BR /><BR /></SPAN></LI></UL></LI><LI><SPAN>Move multiple ABAP Classes / Objects into a new package ( currently is only one possible )<BR /><BR /></SPAN></LI><LI><SPAN>Allow method call as parameters for functions modules instead of only variables. #ABAPCore<BR /></SPAN></LI><LI><SPAN>Auto Ref</SPAN><SPAN>r</SPAN><SPAN>esh test client on debug start. We are adding new lines in client 100. Than we run test in client 120, but the code is not refreshed, we have to refresh the code in the debugger manually to see the cursor on the correct lines.<BR /><BR /></SPAN></LI><LI><SPAN>Debugger, </SPAN><SPAN>compare two structures in a comfortable view. Example old and new data.<BR /><BR /></SPAN></LI><LI><SPAN><STRIKE>Allow method (getter) call in where clause </STRIKE> #ABAPCore<BR /></SPAN><SPAN>Works in 1909: select single * from wbhk where tkonn = @( item->get_tkonn( ) ) into @data(test).<BR /></SPAN></LI><LI><SPAN>Refactoring: add push-down method (additionally to pull-up method ; or is is called pull-down) - with selection of subclass. <BR /><BR /></SPAN></LI><LI><SPAN>Show CDS </SPAN><SPAN>abapdoc </SPAN><SPAN>comments (/**...*/) in Element View (just like abapdoc in classes) </SPAN><SPAN>[including </SPAN><SPAN>@link</SPAN><SPAN> might work automatically</SPAN><SPAN>]<BR /><BR /></SPAN></LI><LI><SPAN>Markdown in abapdoc (or other structuring features - <ul><li></li> is very cumbersome; but also headings, bold, external links, etc.)<BR /><BR /></SPAN></LI><LI><SPAN>Fix abapdoc export, improve and add other elements e.g. </SPAN><SPAN>ddic, </SPAN><SPAN>CDS Views </SPAN><SPAN>; add adt links; initial page, navigation<BR /><BR /></SPAN></LI><LI><SPAN>Method signature (shift-Enter) provide functional signature </SPAN><UL class=""><LI><SPAN>data(matnr) = get_matnr( vbeln = vbeln posnr = posnr )</SPAN><SPAN> instead of</SPAN></LI><LI><SPAN>get_matnr( exporting vbeln = vbeln posnr = posnr returning matnr = matnr ) <BR /></SPAN></LI><!-- ScriptorEndFragment --></UL></LI><LI>Add to constructor quickfix:<BR />when clicking on an attribute of a class, have an "add to constructor", which would cause adding importing parameter and assignment of this parameter to my attribute. Something like that:<BR />DATA: my_attribute.<BR />METHOD constructor.<BR /> my_attribute = i_my_attribute.<BR />ENDMETHOD. Thanks to <A class="" href="https://www.linkedin.com/feed/update/urn:li:activity:7278747013976887296/#" target="_blank" rel="noopener nofollow noreferrer">Michał B.</A><P> </P></LI></UL><P> </P><P> </P><P>looking forward for your comments.</P><P> </P><P>Former post of feature Requests :</P><P><A href="https://community.sap.com/t5/application-development-blog-posts/adt-feature-requests-after-2-years-of-use-in-project/ba-p/13375168" target="_blank">https://community.sap.com/t5/application-development-blog-posts/adt-feature-requests-after-2-years-of-use-in-project/ba-p/13375168</A></P>2024-12-27T22:30:05.686000+01:00https://community.sap.com/t5/technology-blogs-by-members/switching-from-alv-gui-to-list-report-fiori-restful-abap-programming-is-now/ba-p/13974211Switching from ALV GUI to List Report Fiori RESTful Abap Programming is now easy2025-01-03T15:44:27.909000+01:00SamyDhttps://community.sap.com/t5/user/viewprofilepage/user-id/40609<H2 id="toc-hId-1078470590">List report read-only </H2><P>In this topic will create a simple Fiori List Report without object page. It's recommended to use odata v4 but here we will create both v2 and v4</P><H3 id="toc-hId-1011039804">CDS Model </H3><P>The CDS model is driven by the <A href="https://help.sap.com/docs/SAP_S4HANA_ON-PREMISE/ee6ff9b281d8448f96b4fe6c89f2bdc8/8573b810511948c8a99c0672abc159aa.html" target="_self" rel="noopener noreferrer">VDM</A>(Virtual data model) which follow consistent modeling and naming rules.</P><H4 id="toc-hId-943609018">View entity Basics/Composites</H4><P>Create new data definition language in ADT(need eclipse <span class="lia-unicode-emoji" title=":grinning_face:">😀</span> )</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="01.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206370i856EB2196E579BA2/image-size/large?v=v2&px=999" role="button" title="01.png" alt="01.png" /></span></P><P>DDIC view based are obsoletes, so we only use view entity.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="02.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206374iBE69F208E983FD95/image-size/large?v=v2&px=999" role="button" title="02.png" alt="02.png" /></span></P><P>We don't use table directly beceause it's not clean core, instead we use release CDS, you can see this if they are flagged with "#PUBLIC_LOCAL_API" or release C1 contract in API State.</P><P>Now fill your new CDS :</P><P> </P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS basic purchase orders'
define view entity ZI_MyPurchaseOrders
as select from I_PurchaseOrderAPI01
{
key PurchaseOrder,
PurchaseOrderType,
PurchaseOrderSubtype,
PurchasingDocumentOrigin,
CreatedByUser,
CreationDate,
PurchaseOrderDate,
CashDiscount1Percent,
CashDiscount1Days,
@Semantics.amount.currencyCode: 'DocumentCurrency'
DownPaymentAmount,
DocumentCurrency
}</code></pre><P> </P><P>Compile your CDS, and if you want you can add documentation :</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="03.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206376i593535FEDCFF244B/image-size/large?v=v2&px=999" role="button" title="03.png" alt="03.png" /></span></P><P>Now you can fill your own documentation</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="04.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206377iE73B75CEE21DF16C/image-size/large?v=v2&px=999" role="button" title="04.png" alt="04.png" /></span></P><P>And if you refresh your CDS you can open your documentation or if you press F2 on your object you can see documentation with definition</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="05.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206378iF819CD872209C0E2/image-size/large?v=v2&px=999" role="button" title="05.png" alt="05.png" /></span></P><P>Now we will create our root view entity but you can also create other CDS levels between the two.</P><P>The root view entity is the last level before projection view. We'll go into more detail in the object section on page</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="06.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206379i5DD7D73AACC59991/image-size/large?v=v2&px=999" role="button" title="06.png" alt="06.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="07.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206380i97378B3C5BCAF7F6/image-size/large?v=v2&px=999" role="button" title="07.png" alt="07.png" /></span></P><P>You can use the code below</P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'CDS root purchase orders'
define root view entity ZR_MyPurchaseOrders
as select from ZI_MyPurchaseOrders
{
key PurchaseOrder,
PurchaseOrderType,
PurchaseOrderSubtype,
PurchasingDocumentOrigin,
CreatedByUser,
CreationDate,
PurchaseOrderDate,
CashDiscount1Percent,
CashDiscount1Days,
DownPaymentAmount,
DocumentCurrency
}</code></pre><P> </P><P>Compile</P><H4 id="toc-hId-747095513">View entity Projection View</H4><P>Now you need to create the top level view. Only the fields you have in this view can be displayed.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="08.png" style="width: 548px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206383iA977A2D9FAA2C8A3/image-size/large?v=v2&px=999" role="button" title="08.png" alt="08.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="09.png" style="width: 549px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206384i7C74DED1292FCB08/image-size/large?v=v2&px=999" role="button" title="09.png" alt="09.png" /></span></P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'CDS Projection view Purchase Orders'
define root view entity ZC_MYPURCHASEORDERS
provider contract transactional_query
as projection on ZR_MyPurchaseOrders
{
key PurchaseOrder,
PurchaseOrderType,
PurchaseOrderSubtype,
PurchasingDocumentOrigin,
CreatedByUser,
CreationDate,
PurchaseOrderDate,
CashDiscount1Percent,
CashDiscount1Days,
DownPaymentAmount,
DocumentCurrency
}</code></pre><P> </P><P>As you're pointing to a root cds view, you need to specify the root instruction in the projection view too.</P><P>Also you need to provide a contract, for our example it's "transactional_query", you can bypass this but it's not recommended.</P><P>Compile</P><H4 id="toc-hId-550582008">Metadata Extension</H4><P>The metadata extension is used to arrange elements on the UI application with annotations. You can have multiple levels of <A href="https://help.sap.com/docs/abap-cloud/abap-data-models/metadata-extensions" target="_self" rel="noopener noreferrer">metadata extension</A>. </P><H5 id="toc-hId-483151222">Add fields position in table</H5><P>By default, no fields will be displayed. To achieve this, we're going to add annotations at the CDS level (where they can also be added in the frontend application).</P><P>So firstly you need to add this annotation in your projection view</P><P> </P><pre class="lia-code-sample language-abap"><code>@Metadata.allowExtensions: true</code></pre><P> </P><P>Then to add a field in first position you'll use this annotation</P><P> </P><pre class="lia-code-sample language-abap"><code>"""Metadata extension """
@UI.lineItem: [{ position: 10 },{ importance: #HIGH }]</code></pre><P> </P><P>Increment from 10 to 10 to make reworking easier if you've got a position wrong.</P><H5 id="toc-hId-286637717">Add selection fields(filters) position in table</H5><P> </P><pre class="lia-code-sample language-abap"><code>"""Metadata extension """
@UI.selectionField: [{ position: 10 }]</code></pre><P> </P><H5 id="toc-hId-90124212">Add value helps</H5><P>To add value helps your have two options, one with relationship with foreign key and the second with cds view</P><P>We focus only on the second option. To do this, we'll need a cds view of type value help, which we'll call up and which will return all the values in the database.</P><P> </P><pre class="lia-code-sample language-abap"><code>@Consumption.valueHelpDefinition: [{ entity : {name: '/DMO/I_AGENCY_STDVH', element: 'AgencyID' } }]</code></pre><P> </P><H5 id="toc-hId--106389293">Create and fill your metadata extension</H5><P>Now that we have the three default annotations for a correct list report, we can get started.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="10.png" style="width: 546px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206385i25967E92BD072D56/image-size/large?v=v2&px=999" role="button" title="10.png" alt="10.png" /></span></P><P>Then you can choose to annotate entity or view.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="11.png" style="width: 552px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206386i7F186443285464FA/image-size/large?v=v2&px=999" role="button" title="11.png" alt="11.png" /></span></P><P>Choose view for example</P><P>Now the aim is to add annotations for every field you want</P><P> </P><pre class="lia-code-sample language-abap"><code>@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Purchase Order',
typeNamePlural: 'Purchase Orders'
},
presentationVariant: [{
sortOrder: [{
by: 'PurchaseOrder',
direction: #DESC
}],
visualizations: [{
type: #AS_LINEITEM
}]
}]
}
@Search.searchable: true
annotate view ZC_MYPURCHASEORDERS with
{
@UI.lineItem: [{ position: 10 },{ importance: #HIGH }]
@UI.selectionField: [{ position: 10 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
PurchaseOrder;
@UI.lineItem: [{ position: 20 },{ importance: #HIGH }]
@UI.selectionField: [{ position: 20 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
@Consumption.valueHelpDefinition: [{ entity : {name: 'I_PurchasingDocumentType', element: 'PurchasingDocumentType' } }]
PurchaseOrderType;
@UI.lineItem: [{ position: 30 }]
@UI.selectionField: [{ position: 30 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
PurchaseOrderSubtype;
@UI.lineItem: [{ position: 40 }]
@UI.selectionField: [{ position: 40 }]
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
PurchasingDocumentOrigin;
@UI.lineItem: [{ position: 50 }]
@UI.selectionField: [{ position: 50 }]
CreatedByUser;
@UI.lineItem: [{ position: 60 }]
@UI.selectionField: [{ position: 60 }]
CreationDate;
@UI.lineItem: [{ position: 70 }]
@UI.selectionField: [{ position: 70 }]
PurchaseOrderDate;
@UI.lineItem: [{ position: 80 }]
@UI.selectionField: [{ position: 80 }]
CashDiscount1Percent;
@UI.lineItem: [{ position: 90 }]
@UI.selectionField: [{ position: 90 }]
CashDiscount1Days;
@UI.lineItem: [{ position: 100 }]
@UI.selectionField: [{ position: 100 }]
DownPaymentAmount;
@UI.lineItem: [{ position: 110 }]
@UI.selectionField: [{ position: 110 }]
DocumentCurrency;
}</code></pre><P> </P><H3 id="toc-hId--561068236">Business Services</H3><P>Now we will define entities and create odata service</P><H4 id="toc-hId--1126216117">Service Definition</H4><P>Create new Service Definition</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="16.png" style="width: 550px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206843iEC3CDD51FA53C1C8/image-size/large?v=v2&px=999" role="button" title="16.png" alt="16.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="17.png" style="width: 551px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206844iF0ACAE28C04DB1B6/image-size/large?v=v2&px=999" role="button" title="17.png" alt="17.png" /></span></P><P>Insert the code below</P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Service definition for ZC_MYPURCHASEORDERS'
define service ZUI_MYPURCHORDERS {
expose ZC_MYPURCHASEORDERS as PurchaseOrders;
}</code></pre><P> </P><P>Don't forget to alias your entities</P><H4 id="toc-hId--1322729622">Service Binding</H4><P>Now we'll create our odata service. Here's how to create an odata v2 and v4 service.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="18.png" style="width: 550px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206845i58DDCFFBD608362D/image-size/large?v=v2&px=999" role="button" title="18.png" alt="18.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="19.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206846i73281CFC0046F396/image-size/large?v=v2&px=999" role="button" title="19.png" alt="19.png" /></span></P><P>You need to activate your service binding (ctrl+f3)</P><P>Now you have two way to activate your odata service, use the publish button BUT it's only for testing because the input will be local and cannot be put into a package, or use the t-code /IWFND/V4_ADMIN to transport it in package.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="20.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206853iE570D2434591B9CA/image-size/large?v=v2&px=999" role="button" title="20.png" alt="20.png" /></span></P><P>I advise you to check that there are no errors with the publish option in service binding, as you can sometimes get errors with conversion routines (which are not allowed in view entities with 3 exceptions). Once ok, you can unpublish it and then republish it with the transaction for productive use.</P><P>Now your odata V4 is ready to use.</P><P>For V2 it's the same logic but for productivity you need to activate with t-code /IWFND/MAINT_SERVICE</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="21.png" style="width: 547px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206861i96ABFD1D8D219486/image-size/large?v=v2&px=999" role="button" title="21.png" alt="21.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="22.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206868i056BB6242FE1E613/image-size/large?v=v2&px=999" role="button" title="22.png" alt="22.png" /></span></P><P> </P><H4 id="toc-hId--1519243127">Access control (DCL)</H4><P>If you want to add authorization objects in this application, you can add access control. For example if you want restrict purchase order type with PFCG object. Once you've created your odata service, you'll need to add the authorization objects used in access control in su24.</P><P>Make sure you have enabled authorization control on the root view</P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #CHECK</code></pre><P> </P><P>Create DCL(Access Control) for root view entity :</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="12.png" style="width: 548px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206838i6EB06C9BC549B583/image-size/large?v=v2&px=999" role="button" title="12.png" alt="12.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="13.png" style="width: 699px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206839i87A40AD8DB15BBC7/image-size/large?v=v2&px=999" role="button" title="13.png" alt="13.png" /></span></P><P>Then insert the code below</P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Access control for ZR_MYPURCHASEORDERS'
@MappingRole: true
define role ZR_MYPURCHASEORDERS {
grant
select
on
ZR_MYPURCHASEORDERS
where ( PurchaseOrderType ) = aspect pfcg_auth ( M_BEST_BSA,BSART,actvt = '03' );
}</code></pre><P> </P><P><EM>And of course, if you want to use your own specific authorization object, that's also possible.</EM></P><P>Now create another DCL(Access Control) for projection view. This DCL will only inherit the DCL of the root view.</P><P>Make sure you have enabled authorization control on the projection view</P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #CHECK</code></pre><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="14.png" style="width: 549px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206840i4D205F9F5567CF4D/image-size/large?v=v2&px=999" role="button" title="14.png" alt="14.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="15.png" style="width: 672px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206842i3ED68AD5FEEC3973/image-size/large?v=v2&px=999" role="button" title="15.png" alt="15.png" /></span></P><P>Insert the below code</P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Access control for ZC_MYPURCHASEORDERS'
@MappingRole: true
define role ZC_MYPURCHASEORDERS {
grant
select
on
ZC_MYPURCHASEORDERS
where
inheriting conditions from entity ZR_MyPurchaseOrders;
}</code></pre><P> </P><P> </P><P>Now you just need to add yours authorizations objects in your odata service with t-code SU24, and create role in PFCG and assign to you or users.</P><H3 id="toc-hId--1422353625">Fiori Element</H3><P>Open Business Application Studio or VScode(with configured Fiori tools extension).</P><P>Launch "Fiori open application generator" with command palette(ctrl+shift+p)</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="23.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206880iC739CC8C45981348/image-size/medium?v=v2&px=400" role="button" title="23.png" alt="23.png" /></span></P><P>Select Fiori Element List report and select your system, odata service,project name, options</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="24.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206883i38E0BA2FED585D8E/image-size/medium?v=v2&px=400" role="button" title="24.png" alt="24.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="25.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206884iC8CB402AB2A1109B/image-size/medium?v=v2&px=400" role="button" title="25.png" alt="25.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="26.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206885i4094850D9CCAADC5/image-size/medium?v=v2&px=400" role="button" title="26.png" alt="26.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="27.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206886i0B2D53CDF1288FF9/image-size/medium?v=v2&px=400" role="button" title="27.png" alt="27.png" /></span><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="28.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206887iD7343DCEB12E3281/image-size/medium?v=v2&px=400" role="button" title="28.png" alt="28.png" /></span></P><P>Now your app is ready to test.</P><P>You'll notice that by default it has added a navigation in manifest.json to an object page that we haven't coded in the CDS views. We'll set this aside.</P><pre class="lia-code-sample language-json"><code> },
"PurchaseOrdersObjectPage": {
"type": "Component",
"id": "PurchaseOrdersObjectPage",
"name": "sap.fe.templates.ObjectPage",
"options": {
"settings": {
"editableHeaderContent": false,
"contextPath": "/PurchaseOrders"
}
}
}</code></pre><P>Test your app with command </P><pre class="lia-code-sample language-bash"><code>npm run start</code></pre><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="29.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206889iFBE9E46D6F5C1CFF/image-size/large?v=v2&px=999" role="button" title="29.png" alt="29.png" /></span></P><P>You can also test your value help in purchase order type</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="30.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/206891i4D0A6E5030DB7D57/image-size/large?v=v2&px=999" role="button" title="30.png" alt="30.png" /></span></P><H4 id="toc-hId--1912270137">And congrats, you've got a simple List Report application that respects the new development standards.</H4><P>Of course, this display is very simplistic as we've added very few features, so feel free to dig deeper. You can also extend your application to add a custom filter or a new column. And if the design of the lists reports doesn't suit your needs you can always go for <A href="https://sapui5.hana.ondemand.com/test-resources/sap/fe/core/fpmExplorer/index.html" target="_self" rel="nofollow noopener noreferrer">FPM</A> and even freestyle(but no longer recommended <span class="lia-unicode-emoji" title=":grinning_face:">😀</span> )</P><P> </P><H3 id="toc-hId--1815380635">Technical Catalog</H3><P>If you want to deploy for an Private Cloud/On-Premise system in the Fiori Launchpad, you need to create at least a technical catalog. To do this create your catalog in t-code /UI2/FLPAM an fill your Fiori application technical data(no longer use launchpad designer please)</P><P> </P><H2 id="toc-hId--1718491133">Next steps</H2><P>The next step is to deploy your application on your SAP system. To do this, you'll need to run the deployment configuration (npm run deploy-config). Also you may need to fill in the object page and we'll look at that in a second part. And why not show how to add an action with behavior definition(BDEF).</P>2025-01-03T15:44:27.909000+01:00https://community.sap.com/t5/technology-blogs-by-sap/how-to-implement-quot-readonly-update-quot-for-draft-instances/ba-p/13981904How to implement "readonly : update" for draft instances2025-01-09T17:40:28.603000+01:00Andre_Fischerhttps://community.sap.com/t5/user/viewprofilepage/user-id/55<H1 id="toc-hId-950228718">Introduction</H1><P>Via the customer influence channel the requirement was raised to "a<SPAN>llow to modify a field for a draft entity that is not already created in persistency table, the record only exists in draft table." when the field has been configured as readonly : update in the behavior definition. </SPAN></P><P><SPAN>Since this does not work out of the box, </SPAN><SPAN>I will show how such a behavior, a field which is read-only after the first draft has been saved can be achieved in RAP using the SAP standard. </SPAN></P><P><SPAN> </SPAN></P><H1 id="toc-hId-753715213"><SPAN>Problem description </SPAN></H1><P><SPAN>When a field is being defined as readonly for update </SPAN></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code> field ( readonly : update ) AgencyId;</code></pre><P> </P><P> </P><P><SPAN>and if this application is draft-enabled it turns out, that the field cannot be edited after having provided an intial value in the first dialogue of your application. </SPAN></P><H1 id="toc-hId-557201708"><SPAN>Solution ( implementation ) </SPAN></H1><P><SPAN>You can test this code with sample RAP business object that is being created using the following tutorial: </SPAN></P><P><SPAN><A href="https://developers.sap.com/group.abap-build-fiori-element-rap.html" target="_blank" rel="noopener noreferrer">Build an SAP Fiori elements App Using the ABAP RESTful Application Programming Model (RAP) – Beginner [RAP100] | SAP Tutorials</A></SPAN></P><P><SPAN>The desired behavior can be achieved by using dynamic feature control. Instead of using the statement <STRONG>readonly : update</STRONG> you can use the following syntax in your behavior defintion. </SPAN></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code> field ( features : instance ) AgencyId; </code></pre><P> </P><P> </P><P><SPAN>And in your behavior implementation in the <STRONG>get_instance_features()</STRONG> method you have to implement code that checks if an active instance of the travel entity is available. </SPAN></P><P><SPAN>If yes, the field will be made readonly. If not, and this is only the case when the object is being created as a draft but has not been persisted yet, the field will still be editable. </SPAN></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code> METHOD get_instance_features.
DATA result_line LIKE LINE OF result.
" read relevant travel instance data
READ ENTITIES OF zrap100_r_traveltp_rou IN LOCAL MODE
ENTITY Travel
FIELDS ( AgencyId )
WITH CORRESPONDING #( keys )
RESULT DATA(travels)
FAILED failed.
LOOP AT travels INTO DATA(travel).
SELECT SINGLE * FROM zrap100_r_traveltp_rou
WHERE TravelId = -TravelId
INTO (travel_cds_line).
result_line-%tky = travel-%tky.
IF travel_cds_line IS NOT INITIAL.
result_line-%features-%field-AgencyId = if_abap_behv=>fc-f-read_only .
ELSE.
result_line-%features-%field-AgencyId = if_abap_behv=>fc-f-unrestricted.
ENDIF.
APPEND result_line TO result.
ENDLOOP.
ENDMETHOD.</code></pre><P> </P><P> </P><P> </P><H1 id="toc-hId-360688203"><SPAN>Result</SPAN></H1><P><SPAN>The app now behaves as follows: </SPAN></P><UL class="lia-list-style-type-upper-roman"><LI><SPAN>We create a new travel instance.</SPAN><OL><LI><SPAN>We enter a value for the field <STRONG>AgencyId </STRONG></SPAN></LI><LI><SPAN>and press the <STRONG>"Back"</STRONG> button<BR /><BR /><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="100_create_new_travel.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210298iCF74C5FD0525E055/image-size/large?v=v2&px=999" role="button" title="100_create_new_travel.png" alt="100_create_new_travel.png" /></span></SPAN></LI></OL></LI></UL><P> </P><UL class="lia-list-style-type-upper-roman"><LI><SPAN>We can now see the newly created instance in our drafts</SPAN><OL><LI><SPAN>We select the editing status <STRONG>"Own Draft"</STRONG> </SPAN></LI><LI><SPAN>We select the newly created entity <BR /><BR /><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="200_create_new_travel.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210311i1B657D51ACC61605/image-size/large?v=v2&px=999" role="button" title="200_create_new_travel.png" alt="200_create_new_travel.png" /></span><BR /></SPAN></LI></OL></LI></UL><P> </P><UL><LI>When we now edit the entity again we see that the field <STRONG>AgencyId</STRONG> can still be edited<BR /><OL><LI>We press <STRONG>Create</STRONG> to persist the data.<BR /><BR /><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="300_create_new_travel.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210312iF211AB3EF4948326/image-size/large?v=v2&px=999" role="button" title="300_create_new_travel.png" alt="300_create_new_travel.png" /></span><BR /><BR /></LI></OL></LI></UL><P>The newly created item shows up and we press <STRONG>Edit</STRONG> again<BR /><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="400_create_new_travel.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210315i23631F0E547471BE/image-size/large?v=v2&px=999" role="button" title="400_create_new_travel.png" alt="400_create_new_travel.png" /></span><BR /><BR /><BR /></P><UL><LI>Finally we can see that the field <STRONG>AgencyId</STRONG> has become readonly because an active instance exists. <BR /><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="500_create_new_travel.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210318i8B109F01F55D320F/image-size/large?v=v2&px=999" role="button" title="500_create_new_travel.png" alt="500_create_new_travel.png" /></span></LI></UL>2025-01-09T17:40:28.603000+01:00https://community.sap.com/t5/technology-blogs-by-sap/new-sap-discovery-center-mission-mastering-sap-s-4hana-extension-with-sap/ba-p/13982559New SAP Discovery Center Mission: Mastering SAP S/4HANA Extension with SAP Build2025-01-10T12:27:25.847000+01:00ilya-belozerov-saphttps://community.sap.com/t5/user/viewprofilepage/user-id/1941622<DIV><SPAN>From the very beginning, SAP Build has been introduced as a unified low-code platform, enabling developers of all skill levels to create, extend, and automate business applications with drag-and-drop simplicity. Later, its capabilities were expanded with the integration of Java and JavaScript development, enhanced by AI features. And now the latest enhancements of SAP Build include ABAP development capabilities, advanced generative AI features, and deeper integration with SAP S/4HANA and other business applications. </SPAN></DIV><DIV> </DIV><DIV><SPAN>SAP Build simplifies extension development and accelerates ERP modernization by seamlessly connecting all SAP development tools — ABAP, Java, JavaScript, and low-code — to enable effortless collaboration across diverse skill sets.</SPAN></DIV><DIV> </DIV><DIV><SPAN>Start the new mission </SPAN><A href="https://discovery-center.cloud.sap/missiondetail/4420/4706/?tab=overview" target="_self" rel="nofollow noopener noreferrer"><SPAN>Mastering SAP S/4HANA Extension with SAP Build</SPAN></A><SPAN> to try out the power of the Fusion Development experience provided by SAP Build.</SPAN></DIV><DIV> </DIV><H3 id="toc-hId-1208420263"><SPAN>Who is the mission made for?</SPAN></H3><DIV> </DIV><DIV><SPAN>No matter if you are a professional developer or a citizen developer with small development experience, this mission will guide you to the process of developing your extension application within a few hours.</SPAN></DIV><H3 id="toc-hId-1011906758"><SPAN>What is it about?</SPAN></H3><DIV> </DIV><DIV><SPAN>The tutorial scenario is based on the following story:</SPAN></DIV><DIV> </DIV><DIV><SPAN>Suzan, a medical technician at <EM>SBA Medical Clinic</EM>, noticed a small issue with one of the medical devices during her routine equipment checks. To address it quickly, she used the </SPAN><EM>Service Hub Client</EM><SPAN> mobile app to report the problem directly from her smartphone. The app, powered by SAP's Cloud Application Programming Model (CAP), immediately logged the incident in a central system, ensuring all service details were captured in one place.</SPAN></DIV><DIV> </DIV><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="service-hub.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210593iC6E389AE641A79F5/image-size/medium?v=v2&px=400" role="button" title="service-hub.png" alt="service-hub.png" /></span></P><P> </P><DIV><SPAN>Alex, the service manager at <EM>Health Tech Devices</EM>, received the report through the </SPAN><EM>Service Hub Admin</EM><SPAN> interface. He quickly reviewed the issue, prioritized it, and assigned a technician to fix the problem. Using the ABAP RESTful Application Programming model (RAP) power in background, Alex is able to assign the nearest processor of the issue, seeing all available technicians on the map within a selected range.</SPAN></DIV><DIV> </DIV><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="service-hub-admin.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210594i03EA4EDE8679D0A2/image-size/medium?v=v2&px=400" role="button" title="service-hub-admin.png" alt="service-hub-admin.png" /></span></P><P> </P><H3 id="toc-hId-815393253"><SPAN>What will I do?</SPAN></H3><DIV> </DIV><DIV><SPAN>The final solution consists of several services and applications driven by SAP BTP.</SPAN></DIV><DIV> </DIV><DIV><SPAN><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="diagram.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210596iCDEC4C384E51E94B/image-size/medium?v=v2&px=400" role="button" title="diagram.png" alt="diagram.png" /></span></SPAN></DIV><DIV> </DIV><DIV><SPAN>You will start development by creating and deploying a CAP application using </SPAN><SPAN>SAP Build Code</SPAN><SPAN>. This application will be the heart of the project, processing data for equipment maintenance issues. All the steps will be done using the power of artificial intelligence provided by Joule. You will design a data model, expose it with the services, implement some custom logic and deploy to the Cloud Foundry environment, including SAP HANA artifacts.</SPAN></DIV><DIV> </DIV><DIV><SPAN><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="joule.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210598i7E6F6E8762E08F62/image-size/medium?v=v2&px=400" role="button" title="joule.png" alt="joule.png" /></span></SPAN></DIV><DIV> </DIV><DIV><SPAN>You will then create another background service using </SPAN><SPAN>SAP BTP ABAP environment</SPAN><SPAN>. This will provide the data for the available incident processors. The data includes some processor information and geo-location. The main data of a processor is assumed to come from an SAP S/4HANA Cloud system (Business Partner data). For simplicity, this data is uploaded only once. In real production scenarios, there should be a more comprehensive integration. To reproduce this scenario, you don't need an access to a real SAP S/4HANA Cloud system as you will use the SAP Business Accelerator Hub Sandbox. In addition, you will create a service using the ABAP RESTful Application Programming model to search for the processors within a given distance range using the power of the SAP HANA database geo-engine.</SPAN></DIV><DIV> </DIV><DIV><SPAN><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="rap.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210599i7280CE59CC81F869/image-size/medium?v=v2&px=400" role="button" title="rap.png" alt="rap.png" /></span></SPAN></DIV><DIV> </DIV><DIV><SPAN>To access the data from your front-end applications, you will create SAP BTP destinations.</SPAN></DIV><DIV> </DIV><DIV><SPAN>When all background services are available you will use </SPAN><SPAN>SAP Build Apps</SPAN><SPAN> to create 2 cross-platform applications. You will use all the power of SAP Build Apps hidden behind the drag-and-drop simplicity, including advanced components, complex (but still intuitive) formulas, REST-based integration for non-standard data requests, and so on.</SPAN></DIV><DIV> </DIV><H3 id="toc-hId-618879748"><SPAN>How can I start?</SPAN></H3><DIV> </DIV><DIV><SPAN>Try out the mission in SAP Discovery Center for free. The content of the mission is tested on a regular basis and will be kept up to date by integrating the latest services and features.</SPAN></DIV><DIV> </DIV><DIV><SPAN>Even though this mission involves numerous services and applications, you can complete all the steps from start to finish using the SAP BTP Trial Account.</SPAN></DIV><DIV> </DIV><DIV><SPAN>You are interested in more end-to-end missions? Pick up one of them from SAP Discovery Center.</SPAN></DIV><DIV> </DIV><DIV><SPAN>We are excited to hear your feedback about this mission. Please feel free share your thoughts in the comment section below or reach out to us via Discovery Center support tool.</SPAN></DIV>2025-01-10T12:27:25.847000+01:00https://community.sap.com/t5/application-development-blog-posts/enabling-multiline-editing-capabalities-in-rap/ba-p/13981137Enabling Multiline Editing Capabalities in RAP2025-01-10T14:24:44.888000+01:00Megastarhttps://community.sap.com/t5/user/viewprofilepage/user-id/150899<P><STRONG>Introduction </STRONG></P><UL><LI><SPAN>To enable multi-inline editing also for default root view entities, RAP offers the solution to </SPAN><SPAN>model a technical root entity with just one instance, from which you can navigate to its object page</SPAN><SPAN>. This singleton pattern provides a single entrance point to all master data instances.</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Multi-inline-edit capabilities are always necessary if you want the end user of a UI app to be able to edit, add, and delete all instances directly on a Fiori UI list report without navigating to the object page of one instance. It is always relevant for customizing and maintaining complete table data. Multi-inline capabilities on the UI represent the same feature scope as transaction SM30 in SAP GUI.</SPAN><SPAN> </SPAN></LI></UL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="arunkumarn1998_0-1736402863077.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/209968iD55742E470E4708B/image-size/large?v=v2&px=999" role="button" title="arunkumarn1998_0-1736402863077.png" alt="arunkumarn1998_0-1736402863077.png" /></span></P><P><STRONG>Following Steps to enable Multiline Editing with Singleton instance </STRONG></P><P><SPAN> </SPAN></P><P><SPAN>Step 1: Create Custom Table.</SPAN><SPAN> </SPAN></P><P><SPAN>Step 2: Create Interface view on top of table (Child Entity)</SPAN><SPAN> </SPAN></P><P><SPAN>Step 3: Create root view entity With Reference to standard view</SPAN><SPAN> </SPAN></P><P><SPAN>step 4: Create Consumption view on top of root view and add Metadata.</SPAN><SPAN> </SPAN></P><P><SPAN>step 5: Create Consumption view on top of child view and add Metadata.</SPAN><SPAN> </SPAN></P><P><SPAN>step 6: create behavior definition on top of base root view (mapping)</SPAN><SPAN> </SPAN></P><P><SPAN> make left out join from root view entity to the child table to get all the fields.</SPAN><SPAN> </SPAN></P><P><SPAN>step 7: create behavior definition for root consumption view</SPAN><SPAN> </SPAN></P><P><SPAN> make application as draft enable</SPAN><SPAN> </SPAN></P><P><SPAN>step 8: create draft table for root table</SPAN><SPAN> </SPAN></P><P><SPAN>step 9: create draft table for child table.</SPAN><SPAN> </SPAN></P><P><SPAN>step 10: Create Service Definition for root consumption view</SPAN><SPAN> </SPAN></P><P><SPAN>step 11: Create Service Binding</SPAN><SPAN> </SPAN></P><P><SPAN> Preview application</SPAN><SPAN> </SPAN></P><P> </P><P><SPAN><SPAN class=""><SPAN class="">Step 1: Create Custom Table.</SPAN></SPAN><SPAN class=""> </SPAN></SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Emplyoyee Data'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zemp_a {
key employee_id : abap.char(10) not null;
first_name : abap.char(50);
last_name : abap.char(50);
department : abap.char(20);
joining_date : abap.dats;
is_active : abap.char(1);
changed_by : abap.char(12);
local_last_changed_at : abp_locinst_lastchange_tstmpl;
changed_at : abp_lastchange_tstmpl; </code></pre><P> </P><P><SPAN class=""><SPAN class="">Step 2: Create Interface view on top of table (Child Entity)</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Employee Interface'
//@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_EMP_AR as select from zemp_a
association to parent ZI_SINGLETONE_AR as _Semp
on $projection.EmpSingleton = _Semp.EmpSingleton
{
@EndUserText.label : 'Employee ID'
key employee_id as EmployeeId,
1 as EmpSingleton,
@EndUserText.label: 'First Name'
first_name as FirstName,
@EndUserText.label: 'Last Name'
last_name as LastName,
@EndUserText.label: 'Department'
department as Department,
@EndUserText.label: 'Joining Date'
joining_date as JoiningDate,
@EndUserText.label: 'Status'
is_active as IsActive,
@Semantics.user.lastChangedBy: true
changed_by as ChangedBy,
// ETag Field
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
// Total ETag Field
@Semantics.systemDateTime.lastChangedAt: true
changed_at as ChangedAt,
_Semp
} </code></pre><P> </P><P><SPAN>Step 3: Create root view entity (Singleton) With Reference to standard view.</SPAN><SPAN> </SPAN></P><P><SPAN> make left outer join in the root view entity to access all fields from the employee table</SPAN><SPAN> .</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Employee Singletone Interface'
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_SINGLETONE_AR as select from I_Language
left outer join zemp_a as zemp on 1 = 1 // to get all the field from the table
composition[ 0..* ] of ZI_EMP_AR as _EMP
{
key 1 as EmpSingleton,
max(zemp.changed_at) as maxChangedAt, //Done for total etag
_EMP
}
where I_Language.Language = $session.system_language </code></pre><P> </P><P><SPAN class=""><SPAN class="">step </SPAN><SPAN class="">4:</SPAN><SPAN class=""> Create Consumption view on top of root view.</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption view for Singletone Employee'
@Metadata.ignorePropagatedAnnotations: true
@UI.headerInfo: {
typeName: 'Manage Employee',
typeNamePlural: 'Employee Singleton',
title: {
type: #STANDARD,
value: 'EmpSingleton',
targetElement: '_EMP'
} }
define root view entity ZC_SINGLETONE
provider contract transactional_query
as projection on ZI_SINGLETONE_AR
{
@UI.facet: [{
purpose: #STANDARD,
parentId: '',
position: 10,
label: 'Employee Multil inline Edit',
type: #LINEITEM_REFERENCE,
targetElement: '_EMP'
}]
@UI.lineItem: [{ position: 10 }]
key EmpSingleton,
maxChangedAt, //done for total etag field
/* Associations */
_EMP : redirected to composition child ZC_EMP_AR </code></pre><P> </P><P><SPAN class=""><SPAN class="">step </SPAN><SPAN class="">5:</SPAN><SPAN class=""> Create Consumption view on top of child view.</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption view for Employees'
//@Metadata.ignorePropagatedAnnotations: true
@UI: { headerInfo: {
typeName: 'Employee',
typeNamePlural: 'Employees',
title: {
type: #STANDARD,
label: 'Employee',
value: 'EmployeeId'
} }
}
define view entity ZC_EMP_AR
as projection on ZI_EMP_AR
{
@UI.facet: [{
type:#IDENTIFICATION_REFERENCE
}]
@UI:{ lineItem: [{ position: 10 }], identification: [{ position: 10 }] }
key EmployeeId,
// <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>:{ lineItem: [{ position: 20 }], identification: [{ position: 20 }] }
EmpSingleton,
@UI:{ lineItem: [{ position: 30 }], identification: [{ position: 30 }] }
FirstName,
@UI:{ lineItem: [{ position: 40 }], identification: [{ position: 40 }] }
LastName,
@UI:{ lineItem: [{ position: 50 }], identification: [{ position: 50 }] }
Department,
@UI:{ lineItem: [{ position: 60 }], identification: [{ position: 60 }] }
JoiningDate,
@UI:{ lineItem: [{ position: 70 }], identification: [{ position: 70 }] }
IsActive,
// <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1445379">@ui</a>:{ lineItem: [{ position: 80 }], identification: [{ position: 80 }] }
// ChangedBy,
// LocalLastChangedAt,
// ChangedAt,
_Semp : redirected to parent ZC_SINGLETONE
} </code></pre><P> </P><P><SPAN class=""><SPAN class="">step 6</SPAN><SPAN class="">:</SPAN><SPAN class=""> create behavior definition on top of base root view (</SPAN><SPAN class="">mapping)</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_i_singletone_ar unique;
strict ( 2 );
with draft;
define behavior for ZI_SINGLETONE_AR //alias <alias_name>
with unmanaged save // when we dont want save data to table then defin with unmanaged save
draft table ZDT_SINGLETONE
//persistent table t002
lock master
total etag maxChangedAt
authorization master ( instance )
//etag master <field_name>
##draft_op_not_required //to hide the warnings, create uptade, delete
{
// dont want modify the data for root entity
// create;
// update;
// delete;
field ( readonly ) EmpSingleton;
association _EMP { create; with draft; }
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}
define behavior for ZI_EMP_AR //alias <alias_name>
persistent table zemp_a
draft table ZDT_EMP_AR
lock dependent by _Semp
authorization dependent by _Semp
etag master LocalLastChangedAt
{
update;
delete;
field ( mandatory : create, readonly :update ) EmployeeId;
field ( readonly ) EmpSingleton, ChangedAt, ChangedBy;
field ( mandatory ) FirstName;
association _Semp;
mapping for zemp_a
{
EmployeeId = employee_id;
FirstName = first_name;
LastName = last_name;
Department = department;
JoiningDate = joining_date;
IsActive = is_active;
ChangedBy = changed_by;
ChangedAt = changed_at;
LocalLastChangedAt = local_last_changed_at;
}
} </code></pre><P> </P><P><SPAN>step 07: create behavior definition for root consumption view</SPAN><SPAN> </SPAN></P><P><SPAN> make application as draft enable</SPAN><SPAN> .</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>rojection;
strict ( 2 );
use draft;
define behavior for ZC_SINGLETONE //alias <alias_name>
{
use action Edit;
use action Activate;
use action Discard;
use action Prepare;
use action Resume;
use association _EMP { create; with draft; }
}
define behavior for ZC_EMP_AR //alias <alias_name>
//use etag
{
use update;
use delete;
use association _Semp { with draft; }
} </code></pre><P> </P><P><SPAN class=""><SPAN class="">step 08</SPAN><SPAN class="">: create</SPAN><SPAN class=""> draft table for root table</SPAN><SPAN class="">.</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Draft table for entity ZI_SINGLETONE_AR'
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zdt_singletone {
key empsingleton : abap.int1 not null;
maxchangedat : abap.dec(21,7);
"%admin" : include sych_bdl_draft_admin_inc; </code></pre><P> </P><P><SPAN class=""><SPAN class="">step 09</SPAN><SPAN class="">: create</SPAN><SPAN class=""> draft table for child table.</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Draft table for entity ZI_EMP_AR'
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zdt_emp_ar {
key employeeid : abap.char(10) not null;
empsingleton : abap.int1;
firstname : abap.char(50);
lastname : abap.char(50);
department : abap.char(20);
joiningdate : abap.dats;
isactive : abap.char(1);
changedby : abap.char(12);
locallastchangedat : abp_locinst_lastchange_tstmpl;
changedat : abp_lastchange_tstmpl;
"%admin" : include sych_bdl_draft_admin_inc;
} </code></pre><P> </P><P><SPAN class=""><SPAN class="">step 11</SPAN><SPAN class="">:</SPAN><SPAN class=""> Create Service Definition for root consumption view</SPAN></SPAN><SPAN class=""> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Employee Data Maintainance'
define service ZSR_ENPLOYEE_DATA {
expose ZC_SINGLETONE;
expose ZC_EMP_AR;
} </code></pre><P> </P><P><SPAN>step 11: Create Service Binding</SPAN><SPAN> </SPAN></P><P><SPAN> Preview application</SPAN><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="arunkumarn1998_1-1736404190525.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/209973i312A7D2B33884A63/image-size/large?v=v2&px=999" role="button" title="arunkumarn1998_1-1736404190525.png" alt="arunkumarn1998_1-1736404190525.png" /></span></P><P><SPAN class=""><SPAN class="">Click </SPAN><SPAN class="">Singleton</SPAN> <SPAN class="">Data</SPAN></SPAN><SPAN class=""> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="arunkumarn1998_2-1736404239507.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/209974i2D756DEA835D32BE/image-size/large?v=v2&px=999" role="button" title="arunkumarn1998_2-1736404239507.png" alt="arunkumarn1998_2-1736404239507.png" /></span></P><P><SPAN class=""><SPAN class="">Click on Edit</SPAN><SPAN class=""> (Here you can edit multiple data and save it to the database table.)</SPAN></SPAN><SPAN class=""> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="arunkumarn1998_3-1736404269087.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/209975i9DEAE34C123CFE11/image-size/large?v=v2&px=999" role="button" title="arunkumarn1998_3-1736404269087.png" alt="arunkumarn1998_3-1736404269087.png" /></span></P><P><STRONG><SPAN>Conclusion</SPAN></STRONG><SPAN> </SPAN></P><P><SPAN>Enabling multiline editing in RAP requires careful configuration of both the backend (CDS Views and Business Logic). Proper data types, UI components, and backend handling must be in place to ensure seamless interaction with multiline text fields.</SPAN><SPAN> </SPAN></P><P> </P>2025-01-10T14:24:44.888000+01:00https://community.sap.com/t5/application-development-blog-posts/etag-in-rap/ba-p/13982291ETag In RAP2025-01-10T14:24:58.475000+01:00Vivek_Sahu_21https://community.sap.com/t5/user/viewprofilepage/user-id/1451075<P><SPAN>This blog post provides a beginner-friendly introduction to the concept of ETags in RAP (RESTful ABAP Programming).</SPAN><SPAN> </SPAN></P><P><FONT size="5"><STRONG><SPAN>Introduction</SPAN></STRONG><SPAN> </SPAN></FONT></P><P><SPAN>This is one of the concurrency control approaches</SPAN><SPAN> </SPAN></P><P><SPAN>ETag is used to manage data concurrency, preventing multiple users from overwriting the same record simultaneously, similar to the functionality of lock objects.</SPAN><SPAN> </SPAN></P><P><SPAN><STRONG>Concurrency:</STRONG> Accessing/Updating a resource at the same time by different users. It causes confusion among the users and inconsistency in the excepted output.</SPAN><SPAN> </SPAN></P><P><SPAN>If you use Etag, so multiple user can only read the data but they can't update the data, because the server first check the Etag value.</SPAN><SPAN> </SPAN></P><P><FONT size="5"><STRONG><SPAN>Scenario for Etag in RAP</SPAN></STRONG></FONT><SPAN> </SPAN></P><P><SPAN>Consider a scenario where two users access the same record, and User 1 saves their changes first, the ETag mechanism ensures User 2 cannot overwrite those changes without being aware of the update. This prevents data inconsistencies. In this blog, we'll explore implementing ETag functionality in RAP using a timestamp field.</SPAN><SPAN> </SPAN></P><P><FONT size="5"><STRONG><SPAN>Procedure:</SPAN></STRONG><SPAN> </SPAN></FONT></P><P><FONT color="#808080"><STRONG><U><I>1. Created one database table ‘ZVS_DT_TRAVEL’.</I></U> </STRONG></FONT></P><P><SPAN>The table </SPAN><SPAN>zvs_dt_travel</SPAN><SPAN> holds information related to travel records. It includes key fields like </SPAN><SPAN>travel_id</SPAN><SPAN>, and non-key fields such as </SPAN><SPAN>agency_id</SPAN><SPAN>, </SPAN><SPAN>begin_date</SPAN><SPAN>, </SPAN><SPAN>end_date</SPAN><SPAN>, </SPAN><SPAN>last_changed_by</SPAN><SPAN>, and </SPAN><SPAN>last_changed_at</SPAN><SPAN>. The field </SPAN><SPAN>last_changed_at</SPAN><SPAN> is particularly important because it tracks the last timestamp when the record was modified. This timestamp will be used to generate the ETag value.</SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Table for travel'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zvs_dt_travel {
key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
agency_id : /dmo/agency_id;
begin_date : /dmo/begin_date;
end_date : /dmo/end_date;
last_changed_by : abp_locinst_lastchange_user;
last_changed_at : abp_locinst_lastchange_tstmpl;
}</code></pre><P> </P><P><FONT color="#808080"><SPAN class=""><SPAN class="">This table holds travel records:</SPAN></SPAN></FONT><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1736500272017.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210514i544195B380809174/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_0-1736500272017.png" alt="Vivek_Sahu_21_0-1736500272017.png" /></span></P><P><U><FONT color="#808080"><STRONG><EM>2. <SPAN class=""><SPAN class="">Now create one interface</SPAN> <SPAN class="">view</SPAN><SPAN class=""> ‘ZVS_I_TRAVEL1’</SPAN><SPAN class=""> on top of DB table: -</SPAN></SPAN><SPAN class=""> </SPAN></EM></STRONG></FONT></U></P><P><SPAN>The CDS interface view </SPAN><SPAN>zvs_i_travel1</SPAN><SPAN> selects the relevant fields from the </SPAN><SPAN>zvs_dt_travel</SPAN><SPAN> table, including </SPAN><SPAN>last_changed_at</SPAN><SPAN>. This field (</SPAN><SPAN>last_changed_at</SPAN><SPAN>) will be used for generating the ETag value, as indicated by the </SPAN><SPAN>@Semantics.systemDateTime.localInstanceLastChangedAt</SPAN><SPAN> annotation. This annotation ensures that </SPAN><SPAN>last_changed_at</SPAN><SPAN> is recognized as the field that tracks the last modification time.</SPAN><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1736500460512.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210516i0B9BCC11173A9600/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_0-1736500460512.png" alt="Vivek_Sahu_21_0-1736500460512.png" /></span></P><P><STRONG><SPAN>Code of interface view:</SPAN></STRONG><SPAN> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'interface view for travel'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define root view entity zvs_i_travel1 as select from zvs_dt_travel
{
key travel_id as TravelId,
agency_id as AgencyId,
begin_date as BeginDate,
end_date as EndDate,
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true //annotation marks LastChangedAt as the timestamp for enabling ETag checks.
last_changed_at as LastChangedAt
}</code></pre><P> </P><UL><LI><STRONG><SPAN>ETag Generation</SPAN></STRONG><SPAN>: The </SPAN><SPAN>last_changed_at</SPAN><SPAN> field will act as the ETag value. The ETag is a unique identifier for the version of the record. Whenever the </SPAN><SPAN>last_changed_at</SPAN><SPAN> value changes (which happens when a record is updated), the ETag value will also change.</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><FONT color="#808080"><U><I>3. Now create on consumption view ‘ZVS_C_TRAVEL1’ on top of interface view:</I></U> </FONT></STRONG></P><P><SPAN>The consumption view </SPAN><SPAN>zvs_c_travel1</SPAN><SPAN> projects the data from the interface view </SPAN><SPAN>zvs_i_travel1</SPAN><SPAN>. This view is intended to expose the data for transactional operations, such as </SPAN><SPAN>create</SPAN><SPAN>, </SPAN><SPAN>update</SPAN><SPAN>, and </SPAN><SPAN>delete</SPAN><SPAN>. The consumption view allows clients to interact with the data, but the actual persistence and behavior are managed through the behavior definition.</SPAN><SPAN> </SPAN></P><P><STRONG><SPAN>Code of Projection view:</SPAN></STRONG><SPAN> </SPAN></P><P> </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 zvs_c_travel1
provider contract transactional_query
as projection on zvs_i_travel1
{
key TravelId,
AgencyId,
BeginDate,
EndDate,
LastChangedBy,
LastChangedAt
}</code></pre><P> </P><P><U><STRONG><FONT color="#808080"><I>4. Now create a behavior definition on top of interface view:</I></FONT></STRONG> </U></P><P><SPAN>In the behavior definition for </SPAN><SPAN>zvs_i_travel1</SPAN><SPAN>, the </SPAN><SPAN>LastChangedAt</SPAN><SPAN> field is specified as the </SPAN><STRONG><SPAN>ETag</SPAN></STRONG><SPAN> for concurrency control. It is marked as the </SPAN><SPAN>etag master LastChangedAt</SPAN><SPAN>, ensuring that the value of </SPAN><SPAN>LastChangedAt</SPAN><SPAN> will be used for update validation.</SPAN><SPAN> </SPAN></P><UL><LI><STRONG><SPAN>Update Scenario</SPAN></STRONG><SPAN>: When a client sends an </SPAN><SPAN>UPDATE</SPAN><SPAN> request, it must include the </SPAN><SPAN>If-Match</SPAN><SPAN> header containing the </SPAN><SPAN>LastChangedAt</SPAN><SPAN> timestamp (the ETag value). The system will check this value against the current </SPAN><SPAN>LastChangedAt</SPAN><SPAN> value stored in the database. If the values match, the update will proceed. If the values don't match (meaning the record has been updated by another user), the system will return a </SPAN><SPAN>412 Precondition Failed</SPAN><SPAN> error, preventing the overwrite.</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>Code of Behavior Definition of Interface:</SPAN></STRONG><SPAN> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>managed implementation in class zbp_vs_i_travel1 unique;
strict ( 2 );
define behavior for zvs_i_travel1 //alias <alias_name>
persistent table zvs_dt_travel
lock master
authorization master ( instance )
etag master LastChangedAt //ensures concurrency control using the LastChangedAt field for ETag verification
{
create;
update;
delete;
field ( readonly ) TravelId;
mapping for zvs_dt_travel{
TravelId = travel_id;
AgencyId = agency_id;
BeginDate = begin_date;
EndDate = end_date;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}
}</code></pre><P> </P><P><STRONG><FONT color="#808080"><U><I>5. Now create a behavior definition on top of consumption view:</I></U> </FONT></STRONG></P><P><SPAN>In the behavior definition for the </SPAN><STRONG><SPAN>consumption view</SPAN></STRONG><SPAN> (</SPAN><SPAN>zvs_c_travel1</SPAN><SPAN>), you must specify that </SPAN><STRONG><SPAN>ETag</SPAN></STRONG><SPAN> should be used. This tells RAP that the consumption view will work with ETags when performing operations like create, update, or delete.</SPAN><SPAN> </SPAN></P><UL><LI><STRONG><SPAN>ETag Use</SPAN></STRONG><SPAN>: This line ensures that </SPAN><STRONG><SPAN>ETag</SPAN></STRONG><SPAN> will be used during the </SPAN><SPAN>create</SPAN><SPAN>, </SPAN><SPAN>update</SPAN><SPAN>, and </SPAN><SPAN>delete</SPAN><SPAN> operations. It tells RAP that when a record is updated, the </SPAN><STRONG><SPAN>ETag</SPAN></STRONG><SPAN> value (i.e., </SPAN><SPAN>LastChangedAt</SPAN><SPAN>) should be checked to prevent overwriting concurrent changes.</SPAN><SPAN> </SPAN></LI></UL><P><STRONG><SPAN>Code of Behavior Definition of Projection:</SPAN></STRONG><SPAN> </SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>projection;
strict ( 2 );
define behavior for zvs_c_travel1 alias travel
use etag //ensures ETag validation during create, update, and delete operations
{
use create;
use update;
use delete;
}</code></pre><P> </P><P><STRONG><SPAN>ETag Mechanism in Updating Data</SPAN></STRONG><SPAN>:</SPAN><SPAN> </SPAN></P><P><SPAN>When the client wants to update the travel record, it sends a </SPAN><SPAN>PATCH</SPAN><SPAN> request to the system with the </SPAN><SPAN>If-Match</SPAN><SPAN> header containing the ETag value (i.e., the </SPAN><SPAN>LastChangedAt</SPAN><SPAN> value). The system will compare the </SPAN><SPAN>If-Match</SPAN><SPAN> value with the current </SPAN><SPAN>LastChangedAt</SPAN><SPAN> value in the database.</SPAN><SPAN> </SPAN></P><UL><LI><SPAN>If the </SPAN><SPAN>If-Match</SPAN><SPAN> value matches the current </SPAN><SPAN>LastChangedAt</SPAN><SPAN>, the update is allowed, and the </SPAN><SPAN>LastChangedAt</SPAN><SPAN> is updated to the current timestamp.</SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>If the </SPAN><SPAN>If-Match</SPAN><SPAN> value doesn't match the current </SPAN><SPAN>LastChangedAt</SPAN><SPAN> (i.e., the record has been modified by another user in the meantime), the update is rejected, and the system returns a </SPAN><SPAN>412 Precondition Failed</SPAN><SPAN> error.</SPAN><SPAN> </SPAN></LI></UL><P><SPAN>Now from the Frontend, two different users are accessing the same data at the same time:</SPAN><SPAN> </SPAN></P><P><FONT color="#808080"><EM>User 1: </EM></FONT></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_0-1736501048634.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210521i78A31FF53D4FE640/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_0-1736501048634.png" alt="Vivek_Sahu_21_0-1736501048634.png" /></span></P><P><EM><FONT color="#808080">User 2:</FONT></EM><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_1-1736501048635.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210520i389F7F7D76B60A2F/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_1-1736501048635.png" alt="Vivek_Sahu_21_1-1736501048635.png" /></span></P><P><EM>Now user 1 will change the <STRONG>End Date:</STRONG> </EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_2-1736501048636.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210519iE1828D8DCD9FE1ED/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_2-1736501048636.png" alt="Vivek_Sahu_21_2-1736501048636.png" /></span><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_3-1736501048637.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210523iC794FA481BAFD354/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_3-1736501048637.png" alt="Vivek_Sahu_21_3-1736501048637.png" /></span></P><P><EM>Here we can see that User 1 updated the data successfully.</EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_4-1736501048637.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210524i45643D4BD56FB17F/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_4-1736501048637.png" alt="Vivek_Sahu_21_4-1736501048637.png" /></span></P><P><EM>But here User 2, still viewing the old version (Jan 8, 2025) </EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_5-1736501048638.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210522i4BBC2DD7A67E4CB1/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_5-1736501048638.png" alt="Vivek_Sahu_21_5-1736501048638.png" /></span></P><P><EM>Now User 2 will change End Date to Aug 5, 2025: </EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_6-1736501048639.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210525i44163E0B87BA4BF0/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_6-1736501048639.png" alt="Vivek_Sahu_21_6-1736501048639.png" /></span></P><P><EM>So if user 2 click on save button, so he will get one error: - </EM></P><P><SPAN>(Your changes could not be saved. A more recent version is available. To make changes to the latest version, please refresh the data).</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_7-1736501048639.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210526i049359D0DF8F17BA/image-size/medium?v=v2&px=400" role="button" title="Vivek_Sahu_21_7-1736501048639.png" alt="Vivek_Sahu_21_7-1736501048639.png" /></span></P><P><SPAN>User 2 cannot overwrite User 1's updated record without refreshing to see the latest changes.</SPAN><SPAN> </SPAN></P><P><SPAN>if User 1 updates a record and saves it, User 2, still viewing the old version, cannot overwrite the updated record without refreshing the data. The ETag, generated using a timestamp, ensures only the latest version can be updated, avoiding data inconsistencies.</SPAN><SPAN><BR /></SPAN></P><P><SPAN>If User 2 refreshes the data, they will be able to see the updated version and then update the data.</SPAN><SPAN> </SPAN></P><P><EM>After refreshing:</EM><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_8-1736501452012.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210528i3A0FA341CF5C442D/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_8-1736501452012.png" alt="Vivek_Sahu_21_8-1736501452012.png" /></span></P><P><EM>Now, if User 2 tries to update the data, they can update it:</EM><SPAN> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Vivek_Sahu_21_9-1736501452013.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210527iF4F2AED1DE03DCAB/image-size/large?v=v2&px=999" role="button" title="Vivek_Sahu_21_9-1736501452013.png" alt="Vivek_Sahu_21_9-1736501452013.png" /></span></P><P><FONT size="5"><STRONG><SPAN>Conclusion:</SPAN></STRONG></FONT><SPAN> </SPAN></P><P><SPAN>ETag in RAP ensures data consistency by using a unique value, like a timestamp, to track changes. It prevents users from accidentally overwriting each other's updates.</SPAN><SPAN> </SPAN></P><P> </P>2025-01-10T14:24:58.475000+01:00https://community.sap.com/t5/technology-blogs-by-members/how-to-select-all-rows-and-execute-custom-actions-on-a-list-report-like/ba-p/13984607How to Select All Rows and Execute Custom Actions on a List Report-like Screen2025-01-14T22:03:36.413000+01:00MioYasutakehttps://community.sap.com/t5/user/viewprofilepage/user-id/789<H2 id="toc-hId-1079397930">Introduction</H2><P>In the previous <A href="https://community.sap.com/t5/technology-blogs-by-members/how-to-call-rap-actions-with-table-types-from-a-list-report/ba-p/13969836" target="_self">blog</A>, we explored how to call RAP actions with table types from a List Report. While this approach works effectively for scenarios involving a few selected rows, the "Select All" functionality only selects the rows currently visible on the screen. This constraint makes it unsuitable for use cases requiring bulk selection of large datasets.</P><P>To address this limitation, this blog focuses on how to implement "Select All"-like functionality on a List Report-like screen to execute custom actions. By leveraging the Flexible Programming Model and creating a Custom Page, we can achieve bulk selection and execute actions on all rows, whether visible or not.</P><H2 id="toc-hId-882884425"> </H2><H2 id="toc-hId-686370920">Implementation Approach</H2><P>To achieve "Select All"-like functionality and execute actions on all rows, the following approach is used:</P><UL><LI><STRONG>Retrieve Filter Conditions:</STRONG> Instead of selected rows, the filter conditions from the filter bar are passed to the action, allowing it to operate on all matching rows, even if they are not visible.</LI><LI><STRONG>Customize the Filter Bar:</STRONG> The filter bar displays only fields relevant to the action, and the "Adapt Filter" button is hidden to prevent users from adding additional fields to the filter bar.</LI></UL><P>This application is not intended to be a generic List Report but is specifically for scenarios requiring bulk actions on all rows.</P><P><STRONG>Note:</STRONG> This approach was implemented as part of a proof of concept (PoC) and has not been used in any productive applications.</P><H2 id="toc-hId-489857415"> </H2><H2 id="toc-hId-293343910">Scenario Overview</H2><P>In this blog, we will create an application similar to the one in the previous example, focusing on calculating stock values. The application allows users to specify a <STRONG>Plant</STRONG> (single value) and <STRONG>Location</STRONG> (multiple values) in the filter bar. When the <STRONG>"Get Total Stock Value"</STRONG> action is executed, the total stock value is calculated and displayed in a popup dialog.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_0-1736800205243.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211524iB3A2A62F43AACD40/image-size/large?v=v2&px=999" role="button" title="MioYasutake_0-1736800205243.png" alt="MioYasutake_0-1736800205243.png" /></span></P><H2 id="toc-hId-96830405"> </H2><H2 id="toc-hId--99683100">Development Environment</H2><UL><LI><STRONG>Backend:<SPAN> </SPAN></STRONG>BTP ABAP Environment (trial)</LI><LI><STRONG>Frontend:<SPAN> </SPAN></STRONG>SAP Business Application Studio</LI></UL><H2 id="toc-hId--296196605"> </H2><H2 id="toc-hId--492710110">Development Steps</H2><UL><LI><P><STRONG>Backend</STRONG></P><UL><LI>Table Definition</LI><LI>Defining an Action to Handle Deep Parameters</LI><LI>Implementing Behavior Logic</LI></UL></LI><LI><STRONG>Frontend</STRONG><UL><LI>Creating a Custom Page Application</LI><LI>Adjusting Filter Fields</LI><LI>Implementing the View</LI><LI>Implementing the Controller</LI></UL></LI></UL><H2 id="toc-hId--689223615"> </H2><H2 id="toc-hId--538482763"><STRONG>Backend</STRONG></H2><P>The backend implementation for this application is similar to the one described in the previous blog. As such, the explanation has been omitted here, and only the code is provided for reference.</P><H3 id="toc-hId--1028399275"><STRONG>1. Table Definition</STRONG></H3><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label : 'Product Stock'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zyasu_stock {
key client : abap.clnt not null;
key id : sysuuid_x16 not null;
product_id : abap.char(20);
plant : abap.char(4);
location : abap.char(4);
price : abap.int2;
stock : abap.int2;
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> </P><P> </P><H3 id="toc-hId--1224912780"><STRONG>2. Defining an Action to Handle Deep Parameters</STRONG></H3><P><STRONG>2.1. Behavior Definition</STRONG></P><P> </P><pre class="lia-code-sample language-abap"><code>static action calcStockAmountAll deep parameter ZA_PLANT result [1] ZA_AMOUNT;</code></pre><P> </P><P><STRONG>2.2. Root Abstract Entity</STRONG></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Plant'
define root abstract entity ZA_PLANT
{
plant : abap.char(4);
_location : composition [0..*] of ZA_LOCATION;
}</code></pre><P> </P><P><STRONG>2.3. Child Abstract Entity</STRONG></P><P> </P><pre class="lia-code-sample language-abap"><code>@EndUserText.label: 'Location'
define abstract entity ZA_LOCATION
{
location : abap.char(4);
_plant : association to parent ZA_PLANT;
}</code></pre><P> </P><P><STRONG>2.4. Abstract Behavior Definition</STRONG></P><P> </P><pre class="lia-code-sample language-abap"><code>abstract;
strict ( 2 );
with hierarchy;
define behavior for ZA_PLANT alias Plant
{
association _location;
}
define behavior for ZA_LOCATION alias Location
{
}</code></pre><P> </P><H3 id="toc-hId--1421426285"> </H3><H3 id="toc-hId--1617939790"><STRONG>3. Implement Behavior Logic</STRONG></H3><P> </P><pre class="lia-code-sample language-abap"><code> METHOD calcStockAmountAll.
DATA plant TYPE zr_yasu_stock-Plant.
DATA r_location TYPE RANGE OF zr_yasu_stock-location.
DATA amount TYPE i.
"get plant and storage locations
LOOP AT keys INTO DATA(key).
plant = key-%param-plant.
r_location = VALUE #( FOR loc IN key-%param-_location (
sign = 'I'
option = 'EQ'
low = loc-location ) ).
EXIT. "get the first record of the keys
ENDLOOP.
"select from cds view (not including draft data)
SELECT price,
stock
FROM zr_yasu_stock
WHERE plant =
AND location IN @r_location
INTO TABLE (stock_t).
" calculate stock amount
LOOP AT stock_t INTO DATA(stock).
amount = amount + stock-Price * stock-Stock.
ENDLOOP.
" return result
result = VALUE #( FOR key1 IN keys (
%cid = key1-%cid
%param = VALUE #( amount = amount )
) ).
ENDMETHOD.</code></pre><P> </P><H2 id="toc-hId--1521050288"> </H2><H2 id="toc-hId--1717563793">Frontend</H2><H3 id="toc-hId-2087486991">1. Creating a Custom Page Application</H3><P><SPAN>In SAP Business Application Studio, select the OData service created in the previous step and use the "<STRONG>Custom Page</STRONG>" template to create the application. </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_1-1736800856081.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211530iB607694427D70DFF/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_1-1736800856081.png" alt="MioYasutake_1-1736800856081.png" /></span></P><P><SPAN>Since we want to implement the logic using TypeScript, select the "Enable TypeScript" option in the "Project Attributes" during the project setup process.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_2-1736800876210.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211531iDF33C79C32ECA8CE/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_2-1736800876210.png" alt="MioYasutake_2-1736800876210.png" /></span></P><P>The structure of the generated project is as follows:</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_3-1736801184323.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211532iF66E5D8529517581/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_3-1736801184323.png" alt="MioYasutake_3-1736801184323.png" /></span></P><H3 id="toc-hId-1890973486">2. Adjusting Filter Fields</H3><P>Set the filter fields in the Page Map so that only Plant and Location are displayed in the filter bar.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="MioYasutake_4-1736801427120.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211534iB96E2316EE44DCA5/image-size/medium?v=v2&px=400" role="button" title="MioYasutake_4-1736801427120.png" alt="MioYasutake_4-1736801427120.png" /></span></P><H3 id="toc-hId-1694459981">3. Implementing the View</H3><P>Implement the <STRONG>ext/main/Main.view.xml</STRONG> file as follows. Similar to the List Report, it displays a filter bar, a table, and variant management.</P><P> </P><pre class="lia-code-sample language-markup"><code><mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:macros="sap.fe.macros"
xmlns:f="sap.f" xmlns:macrosTable="sap.fe.macros.table" xmlns:v="sap.ui.fl.variants"
xmlns:html="http://www.w3.org/1999/xhtml" controllerName="miyasuta.selectallaction.ext.main.Main">
<f:DynamicPage id="FilterBarDefault" class="sapUiResponsiveContentPadding">
<f:title>
<f:DynamicPageTitle id="_IDGenDynamicPageTitle1">
<f:heading>
<v:VariantManagement id="vm" for="FilterBar" showSetAsDefault="true" headerLevel="H2" />
</f:heading>
<f:snappedContent>
<Text id="_IDGenText" text="{fbConditions>/filtersTextInfo}" />
</f:snappedContent>
</f:DynamicPageTitle>
</f:title>
<f:header>
<f:DynamicPageHeader id="_IDGenDynamicPageHeader1" pinnable="true">
<VBox id="_IDGenVBox1">
<macros:FilterBar
metaPath="/Stock/@com.sap.vocabularies.UI.v1.SelectionFields"
id="FilterBar"
filterChanged=".onFiltersChanged"
/>
</VBox>
</f:DynamicPageHeader>
</f:header>
<f:content>
<macros:Table metaPath="@com.sap.vocabularies.UI.v1.LineItem" readOnly="true" id="LineItemTable" filterBar="FilterBar">
<macros:actions>
<macrosTable:Action id="_IDGenAction1"
key="getTotalStockValue"
text="Get Total Stock Value"
press=".onGetTotalStockValue"
requiresSelection="false"
/>
</macros:actions>
</macros:Table>
</f:content>
</f:DynamicPage>
</mvc:View></code></pre><P> </P><H3 id="toc-hId-1666130167"> </H3><H3 id="toc-hId-1469616662">4. Implementing the Controller</H3><P>The complete code is available <A href="https://github.com/miyasuta/select-all-action-frontend/blob/main/webapp/ext/main/Main.controller.ts" target="_self" rel="nofollow noopener noreferrer">here</A>.</P><P><STRONG>4.1. Hiding the "Adapt Filter" Button</STRONG></P><P>To hide the "Adapt Filter" button, set the <STRONG>visible</STRONG> property of the button to <STRONG>false</STRONG> in the <STRONG>onBeforeRendring </STRONG>method. While this approach may not be officially recommended, I found it in the following Q&A:</P><P><A href="https://community.sap.com/t5/technology-q-a/cap-disable-visibility-of-adapt-filters-button-in-list-page/qaq-p/12547210" target="_self">CAP: Disable visibility of Adapt Filters button in List Page</A></P><P> </P><pre class="lia-code-sample language-javascript"><code> public onBeforeRendering(): void {
//disable the adapt filter button
const adaptFilter = this.getView()?.byId("miyasuta.selectallaction::StockMain--FilterBar-content-btnAdapt") as Button;
adaptFilter.setVisible(false);
}</code></pre><P> </P><P>The button's ID can be identified using tools like the <A href="https://chromewebstore.google.com/detail/ui5-inspector/bebecogbafbighhaildooiibipcnbngo" target="_self" rel="nofollow noopener noreferrer">UI5 Inspector</A>.</P><P><STRONG>4.2. Calling the Action</STRONG></P><P>First, retrieve the selected values from the filter bar. If the required fields are not specified, return an error.<BR />Next, set the retrieved values as parameters and call the action. Finally, display the result in a popup dialog.</P><pre class="lia-code-sample language-javascript"><code> public onGetTotalStockValue(): void {
//get filter conditions
const { plant, locations } = this.extractFilterConditions();
// validate required parameters
if (!plant) {
MessageBox.error("Select a plant in the filter");
return;
}
// invoke action
const model = this.getModel();
const operation = model?.bindContext("/Stock/" + namespace + "calcStockAmountAll(...)") as ODataContextBinding;
operation.setParameter("plant", plant);
operation.setParameter("_location", locations);
const fnSuccess = () => {
// show total
const result = operation.getBoundContext().getObject() as Result;
const amount = result.amount;
const numberFormat = NumberFormat.getIntegerInstance({
groupingEnabled: true
});
const formattedAmount = numberFormat.format(amount);
MessageBox.show(`${formattedAmount} JPY`, {
title: "Stock Amount"
});
};
const fnError = (error: Error) => {
MessageBox.error(error.message);
};
operation.invoke().then(fnSuccess, fnError);
}</code></pre><P>This is the part of the code that extracts filter conditions from the filter bar, processes them, and returns the extracted plant and location(s).</P><pre class="lia-code-sample language-javascript"><code> private extractFilterConditions(): { plant: string | undefined; locations: Location[] } {
//get filter conditions
const allFilters = this.getAllFilters();
let plantRef = { plant: undefined as string | undefined };
let locations: Array<Location> = [];
allFilters.forEach(filter => {
if (filter.getPath()) {
this.processFilter(filter, plantRef, locations);
} else {
filter.getFilters()?.forEach(innerFilter => this.processFilter(innerFilter, plantRef, locations));
}
});
return { plant: plantRef.plant, locations };
}
private getAllFilters(): Filter[] {
const filterBar = this.getView()?.byId("FilterBar") as FilterBar;
// Get the filters from the FilterBar; the structure of filters[0]
// can either be an object (if a single filter value is set)
// or an array (if multiple filter values are set).
const filters = (filterBar.getFilters() as FilterObject).filters[0];
// If filters[0] contains an array of filters, return it directly
if (Array.isArray(filters?.getFilters())) {
return filters.getFilters() as Filter[];
// If filters[0] is an object, wrap it in an array and return
} else if (filters) {
return [filters];
}
// If no filters are set, return an empty array
return [];
}
private processFilter(filter: Filter, plantRef: { plant: string | undefined }, locations: Location[]): void {
if (filter.getPath() === "Plant") {
plantRef.plant = filter.getValue1();
} else if (filter.getPath() === "Location") {
locations.push({ location: filter.getValue1() });
}
}</code></pre><P> </P><H2 id="toc-hId-1566506164">Conclusion</H2><P>This blog addressed the challenge of being unable to select all rows and execute an action in a List Report. To overcome this, values specified in the filter bar were passed as parameters to the action, achieving functionality similar to "Select All."</P><P>While I considered implementing a similar approach by extending the List Report, I found it to be less feasible for two reasons: the difficulty of retrieving values from the filter bar, and the fact that using the internal controls of the filter bar itself is not appropriate. This made the approach an unsuitable solution.</P><P>The Flexible Programming Model is well-suited for creating applications with a List Report-like appearance while enabling more flexible extensions.</P><P>If you have solved a similar challenge using a different approach, I would appreciate it if you could share your solution in the comments section.</P>2025-01-14T22:03:36.413000+01:00https://community.sap.com/t5/application-development-blog-posts/sap-developer-news-january-16th-2025/ba-p/13988216SAP Developer News, January 16th, 20252025-01-16T21:10:00.023000+01:00thomas_junghttps://community.sap.com/t5/user/viewprofilepage/user-id/139<P><div class="video-embed-center video-embed"><iframe class="embedly-embed" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FBZdboT6EdZw&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DBZdboT6EdZw&image=http%3A%2F%2Fi.ytimg.com%2Fvi%2FBZdboT6EdZw%2Fhqdefault.jpg&type=text%2Fhtml&schema=youtube" width="400" height="225" scrolling="no" title="YouTube embed" frameborder="0" allow="autoplay; fullscreen; encrypted-media; picture-in-picture;" allowfullscreen="true"></iframe></div></P><P><STRONG>Podcast: </STRONG><A href="https://podcast.opensap.info/sap-developers/2025/01/16/sap-developer-news-january-16th-2025/" target="_blank" rel="nofollow noopener noreferrer">https://podcast.opensap.info/sap-developers/2025/01/16/sap-developer-news-january-16th-2025/</A></P><H3 id="toc-hId-1208595999">DESCRIPTION</H3><P><STRONG>Upload Files from Build Apps to DMS, DOX and Other Services</STRONG></P><UL><LI>Video #1: Set Up SAP Build Apps to Work with DMS – <A href="https://youtu.be/lhBB2mM9Nho" target="_blank" rel="nofollow noopener noreferrer">https://youtu.be/lhBB2mM9Nho</A></LI><LI>Video #2: Call DMS from SAP Build Apps – <A href="https://youtu.be/SJt_BzctwbI" target="_blank" rel="nofollow noopener noreferrer">https://youtu.be/SJt_BzctwbI</A></LI><LI>Video #3: Upload a File from Build Apps to DMS – <A href="https://youtu.be/gIW_tHOaNuY" target="_blank" rel="nofollow noopener noreferrer">https://youtu.be/gIW_tHOaNuY</A></LI><LI>Free DMS projects: <A href="https://github.com/sap-tutorials/sap-build-apps/tree/main/projects/dms" target="_blank" rel="nofollow noopener noreferrer">https://github.com/sap-tutorials/sap-build-apps/tree/main/projects/dms</A></LI><LI>Document Management Service Playlist: <A href="https://www.youtube.com/playlist?list=PL6RpkC85SLQCsKSvIOqMzFKW30B4TKXh-" target="_blank" rel="nofollow noopener noreferrer">https://www.youtube.com/playlist?list=PL6RpkC85SLQCsKSvIOqMzFKW30B4TKXh-</A></LI><LI>Ming Kho’s blog post on Build Apps and DMS: <A href="https://community.sap.com/t5/technology-blogs-by-sap/sap-build-apps-upload-files-to-sap-document-management-service-dms/ba-p/13963628" target="_blank">https://community.sap.com/t5/technology-blogs-by-sap/sap-build-apps-upload-files-to-sap-document-management-service-dms/ba-p/13963628</A></LI><LI>Ming Kho’s blog post on Build Apps and DOX: <A href="https://community.sap.com/t5/technology-blogs-by-sap/sap-build-apps-upload-files-to-sap-document-information-extraction-dox/ba-p/13964007" target="_blank">https://community.sap.com/t5/technology-blogs-by-sap/sap-build-apps-upload-files-to-sap-document-information-extraction-dox/ba-p/13964007</A></LI></UL><P><STRONG>CAP December 2024 Release</STRONG></P><UL><LI>Release notes <A href="https://cap.cloud.sap/docs/releases/dec24" target="_blank" rel="nofollow noopener noreferrer">https://cap.cloud.sap/docs/releases/dec24</A></LI></UL><P><STRONG>Joule ABAP Developer Capabilities Early Adopter Program</STRONG></P><UL><LI><A href="https://influence.sap.com/sap/ino/#/campaign/3822" target="_blank" rel="noopener noreferrer">https://influence.sap.com/sap/ino/#/campaign/3822</A></LI></UL><P><STRONG>How to implement "readonly : update" for draft instances</STRONG></P><UL><LI><A href="https://community.sap.com/t5/technology-blogs-by-sap/how-to-implement-quot-readonly-update-quot-for-draft-instances/ba-p/13981904" target="_blank">https://community.sap.com/t5/technology-blogs-by-sap/how-to-implement-quot-readonly-update-quot-for-draft-instances/ba-p/13981904</A></LI></UL><P><STRONG>SAP Fiori Innovation Day & UI5 Road Map 2025</STRONG></P><UL><LI>SAP Fiori Innovation Day Silicon Valley: <A href="https://events.sap.com/noam/sap-fiori-innovation-day-silicon-valley/en/home" target="_blank" rel="noopener noreferrer">https://events.sap.com/noam/sap-fiori-innovation-day-silicon-valley/en/home</A></LI><LI>UI5 Road Map Explorer: <A href="https://roadmaps.sap.com/board?PRODUCT=73554900100800001361&range=CURRENT-LAST#Q1%202025" target="_blank" rel="noopener noreferrer">https://roadmaps.sap.com/board?PRODUCT=73554900100800001361&range=CURRENT-LAST#Q1%202025</A></LI></UL><H3 id="toc-hId-1012082494">CHAPTER TITLES</H3><P>0:00 Intro<BR />0:10 Upload Files from Build Apps to DMS, DOX and Other Services<BR />1:51 CAP December 2024 Releas<BR />5:06 Joule ABAP Developer Capabilities Early Adopter Program<BR />6:02 How to implement "readonly : update" for draft instances<BR />6:58 SAP Fiori Innovation Day & UI5 Road Map 2025</P><H3 id="toc-hId-815568989">Transcription</H3><P><STRONG>[Intro]</STRONG> This is the SAP Developer News for January 16th, 2025.</P><P><STRONG>[Daniel]</STRONG> SAP Build Apps has just released a new flow function that lets you upload documents to the BTP Document Management Service, the document information extraction service, or any service that requires a binary upload. Minko, a developer at SAP Build Apps, created the HTTP Destination and request flow function, which takes a multi-part request body and lets you specify a destination, both of which enable you to upload to the services. He has written two blogs, one on using it with DMS and one on using it with DMS, but I want to point out that I've just released three short videos on how to use this flow function with build apps and DMS, and I want to point out that I've just released three short videos on how to use this flow I've released an entire application that lets you navigate through a DMS repo. So it will list all the documents in the root or any folder in the DMS repo, let you upload documents, let you create folders, and let you delete folders and documents. All you need to do is attach your destination to your DMS repo. And I want to point out that we also have a playlist dedicated just to the document management service. It has videos on setting up DMS, unrelated to SAP Build, as well as how to use it with process automation, and build apps. Links to all of that content are in the description.</P><P><STRONG>[DJ]</STRONG> While most of us were taking some time off over the holiday period recently, the CAP team has kept on working and put out another regular monthly release. December 24 of this. As usual, there are plenty of highlights, some of which I want to bring to your attention here. There are so many I've actually got a list and a read through. Got some notes. And this also sees CAP Node.js at 8.6 and CAP Java at 3.6. Okay, so what have we got? There are changes and improvements in the CDS language and compiler area, specifically For example, a completely rewritten CQN specification using TypeScript declaration files, which in turn brings about improved documentation and also some Intellisense operations that are also improved. There's a new beta feature where foreign key elements of managed associations can be explicitly annotated. Moving to the Node.js flavor of CAPs specifically, there are new compiler related life cycle events. They're also in beta. There are some enhancements to CDS Env. These enhancements relate to source formats and profile-specific endv files. And CDSQL has some enhancements. And these enhancements bring about a more robust operation in general and also some new functions for CQN object construction. In the OData arena, there are also some additions and improvements relating to the OData containment feature, and also a move to allow query option-based provision of function parameters, which some of you, I'm sure, will enjoy. In the Java flavor of CAP, there are some important changes in the area of NPM build plugin support, and also the new Calaisi plugin for the document management service is now open source. Last but not least, in the tools area, there are many enhancements to the CDS REPL. Some of you may have seen these enhancements sort of take shape over the course of the first six episodes of the art and science of CAP, a live stream series that we ran recently with the one and only Daniel Hutzl. So I'll put a link to that also in the description to this item, as well as the link to this December 2024. for Capphire release notes, but also for TypeScript developers out there, you can now just use CDS watch to start the server and it will automatically detect a TypeScript project and under the hood it will run CDSTSX for you. There's also more, even more, in this December 2024 release, but I'll leave it to you to go and check out the release notes in Capphire. Until then, see you online.</P><P><STRONG>[Rich]</STRONG> Hey friends, Rich Heilman here. I just wanted to stop in a bit and let you know about the Joule ABAP Developer Capabilities Early Adopter Program for Customers and Partners. That's right, do you want to check out the Bleeding Edge technology helping ABAP developers become more efficient developers? If so, then go to the Influence. site and register for the early adopters program. Registration started on January 15th and will end on February 15th the same day we plan to release to customers. So again, if you are ready to get your hands dirty with AI and using Joule within ADT to help you with ABAP development, then please sign up for this excellent opportunity to try it out, give us some feedback, and make the product better for all. Thanks to ABAP developers, and we'll see you. See you soon. Bye for now.</P><P><STRONG>[Sheena]</STRONG> You might have noticed that when a field is defined as Read Only for updates in a Draft-enabled application, it cannot be edited after an initial value is provided. Andre Fischer in his latest blog post explains how to achieve the editing of such fields in Draft using the dynamic feature control option. For this, just replace the statement read-only update with features instance in your behavior definition. Then in your behavior implementation method, verify whether an active instance of the entity already exists. If yes, the field will be made read only, however, if no active instance exists, the field will remain editable. Please note that this is applicable only when an object is being created as a draft and has not yet been persisted. Check out the details and sample code in the blog post link provided in the description.</P><P><STRONG>[Nico]</STRONG> Hi everyone and welcome to the SAP Developer News. We have some updates in the Fiori and U5 area that we want to put your attention to. First of all, the SAP Fiori Innovation Day happens on February 5th in Silicon Valley. Definitely check it out if you're in the area. AI is going to be a hot topic, there's going to be a partner session, hands -on sessions and an outlook from the Fiori team on what's to come in the future. Check out the link to register in the future. the description of this video. And also related to Fiori, more UI5. The 2025 Roadmap is out now. Go check it out. If you're interested in UI5, there's some interesting items on there, and go follow. All right, check it out. Hope you see you soon. Bye.</P>2025-01-16T21:10:00.023000+01:00https://community.sap.com/t5/application-development-blog-posts/fiori-apps-in-minutes-using-rap-framework-generator/ba-p/13981185Fiori Apps in Minutes using RAP framework/generator2025-01-17T15:25:36.977000+01:00RajatArorahttps://community.sap.com/t5/user/viewprofilepage/user-id/630464<P><EM>This blog-tutorial will guide you through the process of creating a RAP application using ABAP repository objects generator.</EM></P><P><STRONG>Prerequisites:</STRONG></P><P>SAP system access with eclipse installed. (You can use SAP BTP trial account as well)</P><P><STRONG>Process:</STRONG></P><OL class="lia-list-style-type-disc"><LI><U><EM>Create the required database table</EM></U><BR />Right click on Package --> New --> Other ABAP Repository Object<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_0-1736436807565.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210234i4C2E5B044EB4C2F5/image-size/medium?v=v2&px=400" role="button" title="RajatArora_0-1736436807565.png" alt="RajatArora_0-1736436807565.png" /></span><BR /><BR />Search for database table and click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_0-1736493168027.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210467iD2475CAF760BF5B1/image-size/medium?v=v2&px=400" role="button" title="RajatArora_0-1736493168027.png" alt="RajatArora_0-1736493168027.png" /></span><BR /><BR />Provide name & description for the table and click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_1-1736511806352.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210654i516AFC088DD8FAEA/image-size/medium?v=v2&px=400" role="button" title="RajatArora_1-1736511806352.png" alt="RajatArora_1-1736511806352.png" /></span><BR /><BR />Create TR or select an existing one and click on Finish<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_2-1736512213886.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/210655i3DB744F40155F2FC/image-size/medium?v=v2&px=400" role="button" title="RajatArora_2-1736512213886.png" alt="RajatArora_2-1736512213886.png" /></span><BR /><BR />Add required fields to the table and activate it (you can also create a data element for user_id or can use any existing one)<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_2-1736760031366.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211125i61AF77BF2652804B/image-size/medium?v=v2&px=400" role="button" title="RajatArora_2-1736760031366.png" alt="RajatArora_2-1736760031366.png" /></span><BR /><BR /></LI><LI><U><EM>Generate objects for UI</EM></U><BR />Right click on table name in project explorer and click on 'Generate ABAP Repository Objects'<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_3-1736760232146.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211128i00C729EDE0AA4F17/image-size/medium?v=v2&px=400" role="button" title="RajatArora_3-1736760232146.png" alt="RajatArora_3-1736760232146.png" /></span><BR /><SPAN> </SPAN><BR />Select OData UI Service and click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_4-1736760275260.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211129iFB94C34728D726CC/image-size/medium?v=v2&px=400" role="button" title="RajatArora_4-1736760275260.png" alt="RajatArora_4-1736760275260.png" /></span><BR /><BR />Select Package and click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_5-1736760358419.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211131i3B68A0B628CAA8AE/image-size/medium?v=v2&px=400" role="button" title="RajatArora_5-1736760358419.png" alt="RajatArora_5-1736760358419.png" /></span><BR /><BR />Provide names for all the artifacts/objects to be generated and click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_6-1736763864019.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211237i3904F4CD1027C44C/image-size/medium?v=v2&px=400" role="button" title="RajatArora_6-1736763864019.png" alt="RajatArora_6-1736763864019.png" /></span><BR /><BR />Click on Next<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_7-1736766388256.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211263i4E6682179C0FD829/image-size/medium?v=v2&px=400" role="button" title="RajatArora_7-1736766388256.png" alt="RajatArora_7-1736766388256.png" /></span><P>Select TR and finish</P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_8-1736766483173.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211264i6020C4119D0915F8/image-size/medium?v=v2&px=400" role="button" title="RajatArora_8-1736766483173.png" alt="RajatArora_8-1736766483173.png" /></span><BR /><BR />You can see all the generated objects in the project explorer<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_9-1736766696132.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211265i6524778738AE93BF/image-size/medium?v=v2&px=400" role="button" title="RajatArora_9-1736766696132.png" alt="RajatArora_9-1736766696132.png" /></span><BR /><BR /></LI><LI><U><EM>Publish service<BR /></EM></U>Open Service binding and click on Publish<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_10-1736766928276.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211267i01AF748C9A69E0FD/image-size/medium?v=v2&px=400" role="button" title="RajatArora_10-1736766928276.png" alt="RajatArora_10-1736766928276.png" /></span><BR /><FONT color="#3366FF"><EM>This option to publish an OData <STRONG>V4</STRONG> service through eclipse might not work in an on-premises system, for that I will write another blog soon.</EM></FONT><BR /><BR />Your basic RAP based Fiori application is ready for preview<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_11-1736767134735.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211271i292728B0BDDD34AB/image-size/medium?v=v2&px=400" role="button" title="RajatArora_11-1736767134735.png" alt="RajatArora_11-1736767134735.png" /></span><BR /><BR /></LI><LI><U><EM>Preview Service</EM></U><BR />Select entity set and click on Preview<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_12-1736767905811.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211276i0C19B9B3EA135A04/image-size/medium?v=v2&px=400" role="button" title="RajatArora_12-1736767905811.png" alt="RajatArora_12-1736767905811.png" /></span><BR />As this is a managed app, so few standard features like Create, Edit & Delete are handled by system.<BR /><BR />Try creating a new entry using Create button and the same will be visible on report page<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_13-1736768537156.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211295iB186275D47A3E369/image-size/medium?v=v2&px=400" role="button" title="RajatArora_13-1736768537156.png" alt="RajatArora_13-1736768537156.png" /></span><BR /><BR />This can be checked on table level as well<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_14-1736768629300.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/211299i8B7A8BB206FCC1DA/image-size/medium?v=v2&px=400" role="button" title="RajatArora_14-1736768629300.png" alt="RajatArora_14-1736768629300.png" /></span><BR /><BR /><EM>I will try to enhance this RAP application in future and include the same in my future blogs.</EM></LI></OL>2025-01-17T15:25:36.977000+01:00https://community.sap.com/t5/application-development-blog-posts/rap-messages/ba-p/13988584RAP Messages2025-01-17T15:28:43.512000+01:00Dadapeerhttps://community.sap.com/t5/user/viewprofilepage/user-id/1451098<P><FONT size="5"><STRONG>Introduction :</STRONG></FONT></P><P>In the Restful ABAP Programming Model (RAP), messages play a crucial role in validations as they provide meaningful feedback to the user regarding errors, warnings, or informational prompts. These messages help ensure data integrity and guide users during transactional or CRUD (Create, Read, Update, Delete) operations. And REPORTED and FAILURE structures are used to handle messages effectively during validations and other operations. They provide mechanisms to return meaningful feedback to the user. </P><P>The Reported structure is used to collect and return messages to the caller. These messages can be of various types, such as errors, warnings, or informational messages. </P><P>The Failure structure we have to fill what is cause of that particular failure .</P><P>There are different type of messages in rap such as state messages and transition messages </P><P><STRONG>State message:</STRONG> As state messages are semantically related to the state of business object </P><UL><LI>It belong to particular state of business object instance. </LI></UL><UL><LI>State messages always save in database along with the particular message. </LI></UL><UL><LI>State messages are very useful the draft scenario because in the draft we are saving not only the consistent and we are saving the inconsistent data in the draft table . </LI></UL><P> <STRONG>Transition messages:</STRONG> Since transition messages are semantically related to the current request rather than the state of a business object, they are returned using the REPORTED structure of the corresponding EML statement. And transition messages will be available during the transition from one state to another state it will displayed when displayed once. if user will close it will disappear and it will not save in backend. </P><P>In transition messages it is not important to pass %TKY. </P><P><U><EM>Key Components of Messages: </EM></U></P><P> %TKY: it is important to pass the %TKY in state messages because it will tell this particular messages belong to this behavior </P><P>%element : it will specify from which field the error will raise. We need specify both %element and %TKY it will specify from which field and entity the error raised. </P><P>%path : in this we are specifying error will be from root entity are from child entity </P><P>%op-%create </P><P>%op-%action-action1 : this error came due to create operation or action . </P><P>By this user will get to know error will came due to create operation. </P><P>%STATE_AREA: When this component of type String is populated, the framework treats the message as a state-related message. </P><P>%other: The %OTHER to handle messages that are not related to a specific entity. The %OTHER component is populated with an instance of the message-wrapper class for unbound messages that are not tied to any business object entity. </P><P>%MSG: Contains an instance of the message-wrapper class. </P><P>Let see practical of both state and transition messages </P><P><FONT size="5"><STRONG>Scenarios for messages: </STRONG></FONT></P><P> <STRONG>State messages : </STRONG> </P><P> <STRONG>Scenario for state:</STRONG> When a user attempts to enter or update a subject name in the Fees details, the system should validate that this subject name exists in the exam Details. If the subject name does not exist, an error message should be displayed, preventing the operation. </P><P><EM><STRONG><SPAN class=""><SPAN class="">Behavior definition:</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737093851021.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213300i530904497C93166F/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737093851021.png" alt="Dadapeer_0-1737093851021.png" /></span></P><P><EM><STRONG><SPAN class=""><SPAN class="">Validation method code:</SPAN></SPAN></STRONG></EM></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>METHOD Check_Subject.
READ ENTITIES OF zdp_i_cds_stu IN LOCAL MODE
ENTITY Student
by \_fees
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_fees).
read ENTITIES OF zdp_i_cds_stu in LOCAL MODE
ENTITY student
by \_exam
from CORRESPONDING #( lt_fees )
link data(student_exam_subject).
data(ls_fees) = lt_fees[ 1 ].
select SINGLE from zdp_dt_exam fields subject_name WHERE stuid = _fees-Stuid INTo (ls_subject).
if ls_subject ne ls_fees-SubjectName.
APPEND VALUE #( %tky = ls_fees-%tky ) to failed-zdp_i_fees_m.
APPEND VALUE #(
%tky = ls_fees-%tky
%state_area = 'VALIDATE SUBJECT NAME'
%element-subjectname = if_abap_behv=>mk-on
%path = value #( Student-%tky = student_exam_subject[ key id
source-%tky = ls_fees-%tky ]-target-%tky )
%msg = me->new_message(
id = 'ZDP_MESSAGE_CLASS'
number = '011'
severity = ms-error
v1 = ls_fees-SubjectName
* v2 =
* v3 =
* v4 =
) ) TO reported-zdp_i_fees_m.
ENDIF.
ENDMETHOD.
</code></pre><P> </P><P> </P><P>This my output screen. in that we can see three entities data will be displayed such as student, exam and fees details.</P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737094513203.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213312i6BC490967E71D08A/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737094513203.png" alt="Dadapeer_0-1737094513203.png" /></span></STRONG></P><P>In exam details I pass the subject.</P><P>In fees details if I didn’t pass same subject name then error will raise. </P><P><STRONG>Output:</STRONG> the system generates a message specifying the entity and field with the issue. </P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737095166258.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213330i443E45B062C5DD39/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737095166258.png" alt="Dadapeer_0-1737095166258.png" /></span></STRONG></P><P>in this error we can see that messages is coming from fees details entity and Field name.</P><P><STRONG>Transition messages : </STRONG>are of three type instance bound ,Entity bound ,Unbound Transition .</P><P><STRONG>Instance bound :</STRONG> in instance bound along with the message you are passing messages belong to which instance. </P><P><STRONG>Scenario for transition:</STRONG> In exam details If user didn't provide the marks at that time message will trigger. </P><P><EM><STRONG> Behavior definition: </STRONG></EM></P><P><STRONG><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737095908249.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213333i8C3AE31F0E18D660/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737095908249.png" alt="Dadapeer_0-1737095908249.png" /></span></STRONG></P><P><EM><STRONG><SPAN class=""><SPAN class="">Code:</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></EM></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>METHOD marks_validation.
READ ENTITIES OF zdp_i_cds_stu
ENTITY Student BY \_Exam
FIELDS ( Marks ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_marks).
DATA(ls_marks) = lt_marks[ 1 ].
DATA(lv_marks) = ls_marks-Marks.
IF ls_marks-Marks IS INITIAL.
APPEND VALUE #( %tky = ls_marks-%tky
%msg = new_message_with_text( severity =
if_abap_behv_message=>severity-error
text = 'Please Enter Marks for STUID ' && ' ' && ls_marks-Stuid ) ) TO reported-student.
ENDIF.
ENDMETHOD. </code></pre><P> </P><P> </P><P><EM><STRONG><SPAN class=""><SPAN class="">Output:</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737096394308.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213337iE0AAA99F42A20469/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737096394308.png" alt="Dadapeer_0-1737096394308.png" /></span></P><P><STRONG>Entity bound :</STRONG> </P><P>Entity bound messages are typically displayed in <STRONG>global authorization</STRONG> and<STRONG> global feature control</STRONG> scenarios. In such cases, the instance itself is not available. Therefore, before creating the instance, we check whether the user has the required access. </P><P><STRONG>Scenario:</STRONG> If the user's result_status is <STRONG>failed</STRONG> and is changed to <STRONG>pass</STRONG> by clicking the action button, the system will display a success message after the successful update using an entity-bound message. </P><P> <EM><STRONG>Behavior definition:</STRONG> </EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737096687376.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213338i5C34F7AC8F248922/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737096687376.png" alt="Dadapeer_0-1737096687376.png" /></span></P><P><EM><STRONG><SPAN class=""><SPAN class="">Code :</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></EM></P><P> </P><P> </P><pre class="lia-code-sample language-abap"><code>METHOD change_exam_result_enabler.
MODIFY ENTITIES OF zdp_i_cds_stu IN LOCAL MODE
ENTITY Student
UPDATE FIELDS ( result_status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky result_status = 'P' ) ).
result = VALUE #( FOR key IN keys ( %tky = key-%tky
%param = CORRESPONDING #( key ) ) ) .
APPEND VALUE #( %msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = 'Successfully changed Result_status' ) )
TO reported-student.
ENDMETHOD. </code></pre><P> </P><P> </P><P><EM><STRONG><SPAN class=""><SPAN class="">Output:</SPAN></SPAN><SPAN class=""> </SPAN></STRONG></EM></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_0-1737097024037.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213343iEC2D66F36215B1ED/image-size/large?v=v2&px=999" role="button" title="Dadapeer_0-1737097024037.png" alt="Dadapeer_0-1737097024037.png" /></span></P><P><SPAN class=""><SPAN class="">After </SPAN><SPAN class="">successfully</SPAN><SPAN class=""> update </SPAN></SPAN><SPAN class=""> </SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Dadapeer_1-1737097152804.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213346i070370C5EE4039C0/image-size/large?v=v2&px=999" role="button" title="Dadapeer_1-1737097152804.png" alt="Dadapeer_1-1737097152804.png" /></span></P><P><FONT size="5"><STRONG>Conclusion: </STRONG> </FONT></P><P><SPAN>As state messages are semantically related to the state of business object while transition messages are semantically related to the current request rather than the state of a business object. Both complement each other to enhance user experience and ensure clarity in the RAP model.</SPAN><SPAN> </SPAN></P><P><SPAN> </SPAN></P><P><SPAN> </SPAN></P>2025-01-17T15:28:43.512000+01:00https://community.sap.com/t5/application-development-blog-posts/file-handling-in-rap-unmanaged/ba-p/13988554File Handling In RAP ( Unmanaged )2025-01-17T15:28:55.820000+01:00sanjay22https://community.sap.com/t5/user/viewprofilepage/user-id/1535416<P><SPAN class=""><SPAN class="">File uploads let you add file handling functionality to your applications inside the framework of SAP's Rapid Application Programming (RAP) </SPAN><SPAN class="">methodology</SPAN><SPAN class="">. This gives customers the ability to upload a variety of file formats, including photos, Excel spreadsheets, PDFs, and more.</SPAN></SPAN></P><P><SPAN class=""><SPAN class="">SAP's Rapid Application Programming (RAP) architecture allows you to integrate file handling functionality into your applications through file uploads. Users can now upload a variety of file kinds, including PDFs, Excel spreadsheets, photos, and more.</SPAN></SPAN></P><P><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">OData streams are now supported by the RAP framework thanks to the most recent release of SAP BTP ABAP 2208. You may now make your RAP application capable of handling and </SPAN><SPAN class="">maintaining</SPAN><SPAN class=""> Large Objects (LOBs</SPAN><SPAN class="">).This</SPAN><SPAN class=""> feature enables media handling by giving end users the ability to upload external files in a variety of file formats, including PDF, XLSX, binary, and others.</SPAN></SPAN></SPAN></SPAN></P><P><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">In this Blog we will explore how to upload and handle Large Object such as PDF or Binary files without the need to extend the RAP application in BAS.</SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P><P><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">Large objects are </SPAN><SPAN class="">modelled</SPAN> <SPAN class="">by means of</SPAN><SPAN class=""> the following fields: </SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P><UL><LI><SPAN>Attachment </SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Mime type </SPAN><SPAN> </SPAN></LI></UL><UL><LI><SPAN>Filename</SPAN><SPAN> </SPAN></LI></UL><P><SPAN><SPAN class="">The field Attachment </SPAN><SPAN class="">contains</SPAN><SPAN class=""> the LOB itself in a RAWSTRING format and is technically bound to the field Mime type and Filename using semantics annotation.</SPAN></SPAN></P><P><SPAN><SPAN class=""><SPAN class="">Mime type </SPAN><SPAN class="">represents</SPAN><SPAN class=""> the content type of the attachment uploaded and the values for the fields Mime type and Filename are derived from the field Attachment by the RAP framework based on the maintained CDS annotations. No attachment can exist without its mime type and vice versa.</SPAN></SPAN></SPAN></P><P><SPAN><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">For example, when a TEXT file is uploaded the Mime type field will be derived and populated with ‘APPLICATION/txt’.</SPAN></SPAN></SPAN></SPAN></SPAN></P><P><SPAN><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">1 :</SPAN> <SPAN class="">Create the data element of raw string Datatype for the field that stores the file attachment in the Table.</SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_1-1737095963931.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213334iF224C97528C05AE7/image-size/large?v=v2&px=999" role="button" title="sanjay22_1-1737095963931.png" alt="sanjay22_1-1737095963931.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">2 </SPAN><SPAN class="">:</SPAN><SPAN class=""> Creati</SPAN><SPAN class="">ng the Database table using below fields.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_2-1737096033031.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213335iD65CDC01F457D080/image-size/large?v=v2&px=999" role="button" title="sanjay22_2-1737096033031.png" alt="sanjay22_2-1737096033031.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">3</SPAN><SPAN class=""> :</SPAN> </SPAN><SPAN class=""><SPAN class="">Create the Interface view on Above Database table.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_3-1737096079836.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213336i05104752704EF7E5/image-size/large?v=v2&px=999" role="button" title="sanjay22_3-1737096079836.png" alt="sanjay22_3-1737096079836.png" /></span></P><UL><LI><SPAN>@Semantics.mimeType:</SPAN> <SPAN>true</SPAN><SPAN> => Use the above annotations to Handle the field as Mime Type by Internal Framework and to store the attached file which is usually large data.</SPAN></LI></UL><UL><LI><SPAN> </SPAN><SPAN>@Semantics.largeObject</SPAN> <SPAN>:</SPAN> <SPAN>{</SPAN> <SPAN>mime Type:</SPAN> <SPAN>'mime type',</SPAN> <SPAN>file Name:</SPAN> <SPAN>'filename',</SPAN><SPAN> </SPAN>content Disposition Preference: <SPAN>#ATTACHMENT</SPAN> <SPAN>}</SPAN><SPAN> => In this annotations we have to pass the mime type field name and the field which stores the file name.</SPAN></LI></UL><P><SPAN><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">4</SPAN><SPAN class=""> :</SPAN><SPAN class=""> Create the </SPAN><SPAN class="">Projection View on Interface View.</SPAN></SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1737096789935.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213341i9D39F2D891DD0245/image-size/large?v=v2&px=999" role="button" title="sanjay22_0-1737096789935.png" alt="sanjay22_0-1737096789935.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">5</SPAN><SPAN class=""> :</SPAN><SPAN class=""> Create the meta data extension for the created consumption view.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_1-1737097033139.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213344i28524E0FE13E49F2/image-size/large?v=v2&px=999" role="button" title="sanjay22_1-1737097033139.png" alt="sanjay22_1-1737097033139.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">6</SPAN><SPAN class=""> :</SPAN><SPAN class=""> create the behavior definition for </SPAN><SPAN class="">Interface View </SPAN><SPAN class="">and choose the Implementation type as </SPAN></SPAN><SPAN class=""><SPAN class="">Unmanaged</SPAN></SPAN><SPAN class=""><SPAN class="">. </SPAN></SPAN><SPAN class=""><SPAN class=""><SPAN class=""><SPAN class="">For Media handling it is mandatory to create the OData v4 and with Draft functionality.</SPAN></SPAN></SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1737097882486.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213350i07229CE33F696DF2/image-size/large?v=v2&px=999" role="button" title="sanjay22_0-1737097882486.png" alt="sanjay22_0-1737097882486.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_1-1737098266763.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213352i1B25F9F76A399AD6/image-size/large?v=v2&px=999" role="button" title="sanjay22_1-1737098266763.png" alt="sanjay22_1-1737098266763.png" /></span> </P><P><SPAN class="">Draft table for </SPAN><SPAN class="">the persistent Table.</SPAN></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">7 :</SPAN><SPAN class=""> Create the Implementation class for the behavior definition</SPAN><SPAN class=""> for CRUD operation</SPAN><SPAN class="">.</SPAN></SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>CLASS lhc_zr_sm_t_file_hand DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR zr_sm_t_file_hand RESULT result.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE zr_sm_t_file_hand.
METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE zr_sm_t_file_hand.
METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE zr_sm_t_file_hand.
METHODS read FOR READ
IMPORTING keys FOR READ zr_sm_t_file_hand RESULT result.
METHODS lock FOR LOCK
IMPORTING keys FOR LOCK zr_sm_t_file_hand.
ENDCLASS.
CLASS lhc_zr_sm_t_file_hand IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD create.
zcl_sm_unmanaged_crud=>get_instance( )->create(
EXPORTING
entities = entities
CHANGING
mapped = mapped
failed = failed
reported = reported
).
ENDMETHOD.
METHOD update.
zcl_sm_unmanaged_crud=>get_instance( )->update(
EXPORTING
entities = entities
CHANGING
mapped = mapped
failed = failed
reported = reported
).
ENDMETHOD.
METHOD delete.
CALL METHOD zcl_sm_unmanaged_crud=>get_instance( )->delete(
EXPORTING
keys = keys
CHANGING
mapped = mapped
failed = failed
reported = reported
).
ENDMETHOD.
METHOD read.
zcl_sm_unmanaged_crud=>get_instance( )->read(
EXPORTING
keys = keys
CHANGING
result = result
failed = failed
reported = reported
).
ENDMETHOD.
METHOD lock.
ENDMETHOD.
ENDCLASS.
CLASS lsc_ZR_SM_T_FILE_HAND DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_ZR_SM_T_FILE_HAND IMPLEMENTATION.
METHOD finalize.
ENDMETHOD.
METHOD check_before_save.
ENDMETHOD.
METHOD save.
zcl_sm_unmanaged_crud=>get_instance( )->save_data(
CHANGING
reported = reported
).
ENDMETHOD.
METHOD cleanup.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.</code></pre><P> </P><P> </P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">8 :</SPAN><SPAN class=""> Create the API class for the Implementation class.</SPAN></SPAN></P><P> </P><pre class="lia-code-sample language-abap"><code>CLASS zcl_sm_unmanaged_crud DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
TYPES: tt_std_create TYPE TABLE FOR CREATE zr_sm_t_file_hand,
tt_std_update TYPE TABLE FOR UPDATE zr_sm_t_file_hand,
tt_mapped_early TYPE RESPONSE FOR MAPPED EARLY zr_sm_t_file_hand,
tt_failed_early TYPE RESPONSE FOR FAILED EARLY zr_sm_t_file_hand,
tt_reported_early TYPE RESPONSE FOR REPORTED EARLY zr_sm_t_file_hand,
tt_mapped_late TYPE RESPONSE FOR MAPPED LATE zr_sm_t_file_hand,
tt_reported_late TYPE RESPONSE FOR REPORTED LATE zr_sm_t_file_hand,
tt_keys_read TYPE TABLE FOR READ IMPORT zr_sm_t_file_hand,
tt_keys_delete TYPE TABLE FOR DELETE zr_sm_t_file_hand,
tt_read_result TYPE TABLE FOR READ RESULT zr_sm_t_file_hand.
CLASS-METHODS get_instance RETURNING VALUE(ret_student) TYPE REF TO zcl_sm_unmanaged_crud.
METHODS: create IMPORTING entities TYPE tt_std_create
CHANGING mapped TYPE tt_mapped_early
failed TYPE tt_failed_early
reported TYPE tt_reported_early,
read IMPORTING keys TYPE tt_keys_read
CHANGING result TYPE tt_read_result
failed TYPE tt_failed_early
reported TYPE tt_reported_early,
update IMPORTING entities TYPE tt_std_update
CHANGING mapped TYPE tt_mapped_early
failed TYPE tt_failed_early
reported TYPE tt_reported_early,
delete IMPORTING keys TYPE tt_keys_delete
CHANGING mapped TYPE tt_mapped_early
failed TYPE tt_failed_early
reported TYPE tt_reported_early,
save_data CHANGING reported TYPE tt_reported_late.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA: go_instance TYPE REF TO zcl_sm_unmanaged_crud,
gt_create TYPE TABLE OF zsm_t_file_hand,
gt_update TYPE TABLE OF zsm_t_file_hand,
gr_delete TYPE RANGE OF zr_sm_t_file_hand-DocumentId,
gs_file TYPE zsm_t_file_hand.
ENDCLASS.
CLASS zcl_sm_unmanaged_crud IMPLEMENTATION.
METHOD get_instance.
ret_student = COND #( WHEN go_instance IS BOUND THEN go_instance
ELSE NEW #( ) ).
ENDMETHOD.
METHOD create.
gt_create = CORRESPONDING #( entities MAPPING FROM ENTITY ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<lfs_entities>).
IF gt_create IS NOT INITIAL.
gt_create[ 1 ]-client = sy-mandt.
gt_create[ 1 ]-last_changed_by = sy-uname.
GET TIME STAMP FIELD DATA(lv_timestamp).
gt_create[ 1 ]-last_changed_at = lv_timestamp.
mapped-zr_sm_t_file_hand = VALUE #( ( %cid = <lfs_entities>-%cid
%key = <lfs_entities>-%key
%is_draft = <lfs_entities>-%is_draft ) ).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD save_data.
IF gt_create IS NOT INITIAL.
INSERT zsm_t_file_hand FROM TABLE _create.
CLEAR gt_create[].
ELSEIF gt_update IS NOT INITIAL.
UPDATE zsm_t_file_hand FROM TABLE _update.
CLEAR gt_update[].
ELSEIF gr_delete IS NOT INITIAL.
DELETE FROM zsm_t_file_hand WHERE document_id IN _delete.
CLEAR gr_delete[].
ENDIF.
ENDMETHOD.
METHOD update.
DATA : lt_update_x TYPE STANDARD TABLE OF zsm_ts_boolean,
lt_update TYPE STANDARD TABLE OF zsm_t_file_hand.
lt_update = CORRESPONDING #( entities MAPPING FROM ENTITY ).
lt_update_x = CORRESPONDING #( entities MAPPING FROM ENTITY USING CONTROL ).
IF lt_update IS NOT INITIAL.
*
SELECT * FROM zsm_t_file_hand FOR ALL ENTRIES IN _update
WHERE document_id = _update-document_id
INTO TABLE (lt_result_old).
ENDIF.
GET TIME STAMP FIELD DATA(lv_timestamp).
gt_update = VALUE #(
FOR x = 1 WHILE x LE lines( lt_update )
LET ls_control_flag = VALUE #( lt_update_x[ x ] OPTIONAL )
ls_new = VALUE #( lt_update[ x ] OPTIONAL )
ls_old = VALUE #( lt_result_old[ document_id = ls_new-document_id ] OPTIONAL )
IN
(
client = sy-mandt
document_id = COND #( WHEN ls_control_flag-document_id IS INITIAL
THEN ls_old-document_id )
filename = COND #( WHEN ls_control_flag-filename IS NOT INITIAL
THEN ls_new-filename ELSE ls_old-filename )
attachment = COND #( WHEN ls_control_flag-attachment IS NOT INITIAL
THEN ls_new-attachment ELSE ls_old-attachment )
mimetype = COND #( WHEN ls_control_flag-mimetype IS NOT INITIAL
THEN ls_new-mimetype ELSE ls_old-mimetype )
created_at = COND #( WHEN ls_control_flag-created_at IS INITIAL
THEN ls_old-created_at )
created_by = COND #( WHEN ls_control_flag-created_by IS INITIAL
THEN ls_old-created_by )
last_changed_at = COND #( WHEN ls_control_flag-last_changed_at IS INITIAL
THEN lv_timestamp )
last_changed_by = COND #( WHEN ls_control_flag-last_changed_by IS INITIAL
THEN sy-uname )
) ).
ENDMETHOD.
METHOD read.
SELECT * FROM zsm_t_file_hand FOR ALL ENTRIES IN
WHERE document_id = -DocumentId
INTO TABLE (lt_result).
result = CORRESPONDING #( lt_result MAPPING TO ENTITY ).
ENDMETHOD.
METHOD delete.
DATA: lt_delete TYPE STANDARD TABLE OF zsm_t_file_hand.
lt_delete = CORRESPONDING #( keys MAPPING FROM ENTITY ).
gr_delete = VALUE #(
FOR ls_delete IN lt_delete
sign = 'I' option = 'EQ' ( low = ls_delete-document_id )
).
ENDMETHOD.
ENDCLASS.</code></pre><P> </P><P> </P><P>Step 7 : create the behavior definition for the Projection View.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1737098826915.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213356iDE6C43058D97EEF7/image-size/large?v=v2&px=999" role="button" title="sanjay22_0-1737098826915.png" alt="sanjay22_0-1737098826915.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">8</SPAN><SPAN class=""> :</SPAN><SPAN class=""> Create the Service definition</SPAN><SPAN class=""> for the consumption view.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_1-1737098906787.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213359i0EF4E3BFB4353FF2/image-size/large?v=v2&px=999" role="button" title="sanjay22_1-1737098906787.png" alt="sanjay22_1-1737098906787.png" /></span></P><P><SPAN class=""><SPAN class="">Step </SPAN><SPAN class="">9</SPAN><SPAN class=""> :</SPAN><SPAN class=""> Create the Service Binding for Created Service definition and Choose the Binding type as </SPAN></SPAN><SPAN class="">OData V</SPAN><SPAN class="">4</SPAN><SPAN class=""> ,</SPAN><SPAN class="">activate and publish the service</SPAN><SPAN class="">.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_2-1737098953938.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213360i6C2B89ED521FFD7B/image-size/large?v=v2&px=999" role="button" title="sanjay22_2-1737098953938.png" alt="sanjay22_2-1737098953938.png" /></span></P><P>Preview the Application and click on create to upload the file.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_0-1737099647005.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213364i361C2B1E2BAE7D63/image-size/large?v=v2&px=999" role="button" title="sanjay22_0-1737099647005.png" alt="sanjay22_0-1737099647005.png" /></span></P><P><SPAN class=""><SPAN class="">Click on upload icon near to the attachment field,</SPAN><SPAN class=""> select the file,</SPAN> <SPAN class="">file</SPAN><SPAN class=""> name will be auto filled </SPAN><SPAN class="">and</SPAN><SPAN class=""> fill the Mime type</SPAN><SPAN class=""> manually</SPAN><SPAN class="">.</SPAN></SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_1-1737099684894.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213367i2EB65C040A21E06C/image-size/large?v=v2&px=999" role="button" title="sanjay22_1-1737099684894.png" alt="sanjay22_1-1737099684894.png" /></span></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_3-1737099810705.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213369i87EBE064560E4CD8/image-size/large?v=v2&px=999" role="button" title="sanjay22_3-1737099810705.png" alt="sanjay22_3-1737099810705.png" /></span></P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sanjay22_4-1737099820369.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213371iA6E04F65B64633E0/image-size/large?v=v2&px=999" role="button" title="sanjay22_4-1737099820369.png" alt="sanjay22_4-1737099820369.png" /></span></P><P> </P><P> </P>2025-01-17T15:28:55.820000+01:00https://community.sap.com/t5/technology-blogs-by-sap/cds-view-real-world-analogy/ba-p/13988946CDS view - real world analogy2025-01-17T22:35:58.201000+01:00Slowly_Goinghttps://community.sap.com/t5/user/viewprofilepage/user-id/1911117<P>To better understand and remember the complex things I always use some real world analogy. In this blog I will provide you my real world analogy for CDS Views. </P><P>Definition of <SPAN>ABAP Core Data Services that I found <A href="https://developers.sap.com/tutorials/abap-dev-adt-create-cds-view..html" target="_self" rel="noopener noreferrer">here</A> says that CDS is an <STRONG>infrastructure</STRONG> for <STRONG>defining and consuming</STRONG> <STRONG>semantically rich data models</STRONG> in ABAP. Did you understand something? I am not <span class="lia-unicode-emoji" title=":neutral_face:">😐</span></SPAN></P><P>From the definition we can extract the main parts:</P><OL><LI><SPAN><STRONG>infrastructure</STRONG></SPAN></LI><LI><SPAN>for <STRONG>defining and consuming</STRONG></SPAN></LI><LI><SPAN><STRONG>semantically rich data models</STRONG></SPAN></LI></OL><H3 id="toc-hId-1208602819"><span class="lia-unicode-emoji" title=":microscope:">🔬</span> let's look closer</H3><P>1. CDS is some <STRONG>infrastructure</STRONG>. OK, but we are don't know yet what exact is infrastructure about.</P><P>2. This infrastructure is for <STRONG>defining and consuming</STRONG> some data? This is make sense! In the SAP world it's all about the data, right? And CDS helps us to defining and consuming data? But we already can do it with normal tables and table views... Until now it is not clear why we need some extra tool for this.</P><P>3. Defining and consuming <STRONG>semantically rich data models</STRONG>. Ah maybe this make sense! CDS help us to work with semantically rich data models. But wait... What does hack mean semantically rich data models? I found such example of semantic definition:</P><P style=" padding-left : 30px; "><EM>Semantics is the study of meaning in language. It can be applied to entire texts or to single words. For example, "destination" and "last stop" technically mean the same thing, but students of semantics analyze their subtle shades of meaning.</EM></P><P>OK, so semantic its a meaning of something. And what about data model?</P><P style=" padding-left : 30px; "><EM>A <STRONG>data model</STRONG> is an <A class="" title="Abstract model" href="https://en.wikipedia.org/wiki/Abstract_model" target="_blank" rel="noopener nofollow noreferrer">abstract model</A> that organizes elements of <A title="Data" href="https://en.wikipedia.org/wiki/Data" target="_blank" rel="noopener nofollow noreferrer">data</A> and <A title="Standardization" href="https://en.wikipedia.org/wiki/Standardization" target="_blank" rel="noopener nofollow noreferrer">standardizes</A> how they relate to one another and to the properties of real-world <A title="Entity" href="https://en.wikipedia.org/wiki/Entity" target="_blank" rel="noopener nofollow noreferrer">entities</A>. For instance, a data model may specify that the data element representing a car be composed of a number of other elements which, in turn, represent the color and size of the car and define its owner.</EM></P><P>Hmm... how can the car data model be semantically rich? To understand this, let’s create an analogy that relates it to the real world.</P><H3 id="toc-hId-1012089314"> </H3><H3 id="toc-hId-815575809"><STRONG>Real-World Analogy: Car Registration Office <span class="lia-unicode-emoji" title=":office_building:">🏢</span> <span class="lia-unicode-emoji" title=":automobile:">🚗</span> </STRONG></H3><P>A CDS view can be compared to a car registration office that organizes, retrieves, and presents vehicle data for various purposes, such as issuing registration certificates or generating reports. Here's how the analogy works:</P><H3 id="toc-hId-619062304"><STRONG>Step 1: A Basic Data Model</STRONG></H3><P>Raw data about cars and owners is stored in separate database tables. For example <STRONG>cars </STRONG>table might look like this:</P><TABLE width="476px"><TBODY><TR><TD width="62.3828px" height="30px"><STRONG>Car_ID</STRONG></TD><TD width="56.4297px" height="30px"><STRONG>Brand</STRONG></TD><TD width="58.2031px" height="30px"><STRONG>Model</STRONG></TD><TD width="67.8828px" height="30px"><STRONG>Size</STRONG></TD><TD width="148.672px" height="30px"><STRONG>Manufacture_Year</STRONG></TD><TD width="85.6875px" height="30px"><STRONG>Owner_ID<BR /></STRONG></TD></TR><TR><TD width="62.3828px" height="30px">C001</TD><TD width="56.4297px" height="30px">BMW</TD><TD width="58.2031px" height="30px">X5</TD><TD width="67.8828px" height="30px">Large</TD><TD width="148.672px" height="30px">2018</TD><TD width="85.6875px" height="30px">O001</TD></TR><TR><TD width="62.3828px" height="57px">C002</TD><TD width="56.4297px" height="57px">Tesla</TD><TD width="58.2031px" height="57px">Model 3</TD><TD width="67.8828px" height="57px">Medium</TD><TD width="148.672px" height="57px">2022</TD><TD width="85.6875px" height="57px">O002</TD></TR></TBODY></TABLE><P> </P><P>and <STRONG>owners</STRONG> table might look like this:</P><TABLE width="331px"><TBODY><TR><TD width="85.6875px" height="30px"><STRONG>Owner_ID</STRONG></TD><TD width="85.2188px" height="30px"><STRONG>First_Name</STRONG></TD><TD width="94.8672px" height="30px"><STRONG>Last_Name</STRONG></TD><TD width="67.8828px" height="30px"><STRONG>Email</STRONG></TD></TR><TR><TD width="85.6875px" height="30px">O001</TD><TD width="85.2188px" height="30px">Bob</TD><TD width="94.8672px" height="30px">Marlie</TD><TD width="67.8828px" height="30px">bob.marlie@sap.com</TD></TR><TR><TD width="85.6875px" height="57px">O002</TD><TD width="85.2188px" height="57px">James</TD><TD width="94.8672px" height="57px">Bond</TD><TD width="67.8828px" height="57px">james.bond@sap.com</TD></TR></TBODY></TABLE><P>While this tables is useful, it lacks context or relationships between the data. For example:</P><UL><LI>What does "Size" really mean? Is it a physical dimension or a category (e.g., SUV vs. sedan)?</LI><LI>Who is "Owner"?</LI></UL><P>This tables is <STRONG>not</STRONG> <STRONG>semantically rich</STRONG> because it doesn’t provide additional meaning or relationships between data elements.</P><HR /><H3 id="toc-hId-422548799"><STRONG>Step 2: Adding Semantic Layers</STRONG></H3><P>Using CDS views, we enrich the car data model by:</P><OL><LI><P><STRONG>Adding Descriptive Metadata</STRONG></P><UL><LI>Define "Size" as an enumeration (e.g., small, medium, large) with clear business rules.</LI><LI>Specify relationships, such as the "Owner" being a reference to the Owners table.</LI></UL></LI><LI><P><STRONG>Creating Relationships</STRONG></P><UL><LI>Link the car to additional entities, such as "Owner".</LI></UL></LI><LI><P><STRONG>Using Calculated Fields</STRONG></P><UL><LI>Create a derived field, such as Car_Age (based on the car's manufacturing year).</LI></UL></LI></OL><P>Here’s an enriched view of the same table with CDS:</P><P>If you query this CDS view, you’d get:</P><TABLE width="632px"><TBODY><TR><TD width="53.4844px" height="30px"><STRONG>Car_ID</STRONG></TD><TD width="112.508px" height="30px"><STRONG>Manufacturer</STRONG></TD><TD width="58.2031px" height="30px"><STRONG>Model</STRONG></TD><TD width="154.32px" height="30px"><STRONG>Manufacturing_Year</STRONG></TD><TD width="85.75px" height="30px"><STRONG>Size_Text</STRONG></TD><TD width="113.266px" height="30px"><STRONG>Owner_Name</STRONG></TD><TD width="66.6719px" height="30px"><STRONG>CarAge</STRONG></TD></TR><TR><TD width="53.4844px" height="30px">C001</TD><TD width="112.508px" height="30px">BMW</TD><TD width="58.2031px" height="30px">X5</TD><TD width="154.32px" height="30px">2018</TD><TD width="85.75px" height="30px">SUV</TD><TD width="113.266px" height="30px">Bob</TD><TD width="66.6719px" height="30px">7</TD></TR><TR><TD width="53.4844px" height="57px">C002</TD><TD width="112.508px" height="57px">Tesla</TD><TD width="58.2031px" height="57px">Model 3</TD><TD width="154.32px" height="57px">2022</TD><TD width="85.75px" height="57px">Sedan</TD><TD width="113.266px" height="57px">James</TD><TD width="66.6719px" height="57px">3</TD></TR></TBODY></TABLE><P>Now when someone (e.g., a car owner, law enforcement officer, or auditor) requests specific information, the staff:</P><OL><LI>Combines relevant data from multiple files (tables).</LI><LI>Presents only the necessary information in an organized format (view).</LI></OL><HR /><H3 id="toc-hId-226035294"><STRONG>How CDS Makes it Easier</STRONG></H3><P>CDS views allow you to:</P><UL><LI>Model these semantic layers <STRONG>once</STRONG> and use them consistently across your ABAP applications.</LI><LI>Make your data reusable with <STRONG>associations</STRONG> (instead of static joins).</LI><LI>Ensure all consumers (apps, reports, services) interpret the data in the same meaningful way.</LI></UL><HR /><P>Aha now its more clear! CDS allow us to add more information about the data to allow us to use this information for search or analyze the data more efficient.</P><P>The real world analogy could be a projector (CDS projector <span class="lia-unicode-emoji" title=":grinning_face:">😀</span>) <SPAN class="">which</SPAN> <SPAN class="">shines</SPAN> <SPAN class="">through the database tables and extends/joined/aggregate the data on the projection.</SPAN></P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="CDS projector" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213705i8CD078E0E8C84A42/image-size/large?v=v2&px=999" role="button" title="cds_analogy_png.png" alt="CDS projector" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">CDS projector</span></span>In the CDS view we can see now the semantic, related to the car size. Large become SUV, owner ID become the person name and CDS also calculate the car age based on the manufacturing year. All this additional data we can use to easily search, filter, and analyze. Nice, is it?</P><P class="">Now let see how it was made with <STRONG>CDS view</STRONG> that adds semantic meaning to the raw data. </P><P> </P><pre class="lia-code-sample language-abap"><code>@AbapCatalog.sqlViewName: 'ZCDS_CAR_INFO'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Car Information with Semantics'
define view ZCDS_CarInfo
as select from Cars
inner join Owners on Cars.Owner_ID = Owners.Owner_ID
{
key Cars.Car_ID as CarID,
Cars.Manufacturer,
Cars.Model,
Cars.Manufacturing_Year as ManufacturingYear,
@ObjectModel.text.element: ['Size_Text']
Cars.Size,
case Cars.Size
when 'Small' then 'Hatchback'
when 'Medium' then 'Sedan'
when 'Large' then 'SUV'
else 'Unknown'
end as Size_Text,
Owners.Name as OwnerName,
cast( year( current_date ) - Cars.Manufacturing_Year as INT ) as CarAge,
}</code></pre><P> </P><P>Now this CDS view can be used across multiple apps, reports, and services. Users and developers can work with meaningful data without worrying about low-level table structures. All consumers interpret data the same way (do you remember Large means SUV).</P><P>Thats all from my side about basic understanding of CDS view and the purpose of them. Leave the comment if it was useful for you or not. I will appreciate it <span class="lia-unicode-emoji" title=":thumbs_up:">👍</span></P><P><SPAN class="">Thank</SPAN> <SPAN class="">you</SPAN> <SPAN class="">and</SPAN> <SPAN class="">enjoy</SPAN> <SPAN class="">your</SPAN> <SPAN class="">work</SPAN><SPAN class="">!</SPAN></P>2025-01-17T22:35:58.201000+01:00https://community.sap.com/t5/technology-blogs-by-members/enable-odata-streams-in-rap/ba-p/13990426Enable OData Streams in RAP2025-01-20T06:28:13.387000+01:00pavankumar_reddy90https://community.sap.com/t5/user/viewprofilepage/user-id/189954<P><SPAN><STRONG>Problem statement:</STRONG><BR />How to enable OData Streams such as excel, pdf, Images and other large objects using standard RAP Based application development without using UI5 tooling?</SPAN></P><P><STRONG>Solution:</STRONG></P><P><SPAN>With the latest SAP BTP ABAP Environment 2208 release the RAP framework now supports OData streams. It is now possible to enable your RAP application to maintain and handle Large Objects(LOBs).This feature provides end users an option to upload external files of different file formats such as PDF, XLSX , binary file format and other types hence allowing media handling.<BR /><BR />I am on of the presenter for this topic at ABAP Conference and int the below youtube recording. This topic covers content related to how to enable large objects using RAP (ABAP RESTful Programming Model ). Upload functionality using custom actions, download functionality using custom actions, how to use XCO library to read and write XLSX content and some useful links which can be explored about OData Streams in RAP.</SPAN></P><P><BR />ABAP Conference recording: <A href="https://www.youtube.com/watch?v=QyPEzRHA9Lo&ab_channel=ABAPConf" target="_blank" rel="noopener nofollow noreferrer">Enable OData Streams in RAP</A></P><P>Slides: <A href="https://abapconf.org/abapconf2024/#/agenda" target="_blank" rel="noopener nofollow noreferrer">https://abapconf.org/abapconf2024/#/agenda</A></P><P>Check for topic "<A class="" href="https://abapconf.org/abapconf2024/#" target="_blank" rel="noopener nofollow noreferrer">Enable OData Streams in RAP</A>" where you can find the link to download slides in pdf document.<BR /><BR />Use cases covered:</P><OL><LI><STRONG>Working with Large Objects</STRONG></LI><LI><STRONG>Upload Functionality using Custom Action</STRONG></LI><LI><STRONG>Download Functionality using Custom Action</STRONG></LI><LI><STRONG>Use XCO library to read and write XLSX Content</STRONG></LI></OL><P><STRONG>Code based GitHub URL's:</STRONG></P><P>1. Upload and Download Functionality application : <A href="https://github.com/rvrrpk/OdataStreamsRAP" target="_blank" rel="noopener nofollow noreferrer">https://github.com/rvrrpk/OdataStreamsRAP</A></P><P>2. Download History Application : <A href="https://github.com/rvrrpk/DownloadHistory" target="_blank" rel="noopener nofollow noreferrer">https://github.com/rvrrpk/DownloadHistory</A></P><P> </P><P> </P><P> </P><P> </P>2025-01-20T06:28:13.387000+01:00https://community.sap.com/t5/application-development-blog-posts/publishing-odata-v4-service-in-a-customizing-client/ba-p/13987743Publishing ODATA v4 service in a customizing client2025-01-21T19:02:11.234000+01:00RajatArorahttps://community.sap.com/t5/user/viewprofilepage/user-id/630464<P><EM>This blog-tutorial will guide you through the process of publishing OData v4 service in a customizing client.</EM></P><P><STRONG>Problem:<BR /><BR /></STRONG>Publishing local service endpoint of service binding 'XXXXX' has encountered a problem<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_0-1736947462304.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212256i1819ABC91F86812E/image-size/medium?v=v2&px=400" role="button" title="RajatArora_0-1736947462304.png" alt="RajatArora_0-1736947462304.png" /></span></P><P>This problem usually occurs if you are working in a customizing client and the settings for the client in section "Changes and transports for client specific objects" are set to one of the options</P><OL><LI>"Automatic recording of changes" or</LI><LI>"No changes allowed"</LI></OL><P>This can be checked using SCC4 transaction<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_1-1736947846675.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212259i6845EDDA29BC1F5E/image-size/medium?v=v2&px=400" role="button" title="RajatArora_1-1736947846675.png" alt="RajatArora_1-1736947846675.png" /></span><BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_2-1736947880312.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212260i49720C4D02DA6A4E/image-size/medium?v=v2&px=400" role="button" title="RajatArora_2-1736947880312.png" alt="RajatArora_2-1736947880312.png" /></span></P><P>This blog mainly focuses on publishing v4 service created based on RAP BO using ADT (eclipse) but can also be referred for publishing any v4 service.</P><P><STRONG>Solution:</STRONG></P><P>Activate the service binding post RAP BO creation using ADT (this will create a service group)<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_3-1736948856852.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212285iC47D3B92324EA26F/image-size/medium?v=v2&px=400" role="button" title="RajatArora_3-1736948856852.png" alt="RajatArora_3-1736948856852.png" /></span></P><P>Go to /N/IWFND/V4_ADMIN<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_4-1736948997395.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212290iA0A85DDEF2964E4E/image-size/medium?v=v2&px=400" role="button" title="RajatArora_4-1736948997395.png" alt="RajatArora_4-1736948997395.png" /></span></P><P>Click on 'Publish Service Groups'<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_5-1737011568687.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212956iA6B685D4B6CDA9AA/image-size/medium?v=v2&px=400" role="button" title="RajatArora_5-1737011568687.png" alt="RajatArora_5-1737011568687.png" /></span></P><P>Select system alias and click on 'Get Service Groups'<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_6-1737011734221.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212957iE640E6120D8EC97B/image-size/medium?v=v2&px=400" role="button" title="RajatArora_6-1737011734221.png" alt="RajatArora_6-1737011734221.png" /></span></P><P>Select the group ID corresponding to the OData service and click on 'Publish Service Groups<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_7-1737011789636.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212958i3830C394662AA81F/image-size/medium?v=v2&px=400" role="button" title="RajatArora_7-1737011789636.png" alt="RajatArora_7-1737011789636.png" /></span></P><P>Update description and click on continue<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_8-1737011902039.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212959iD7D9339229383C6E/image-size/medium?v=v2&px=400" role="button" title="RajatArora_8-1737011902039.png" alt="RajatArora_8-1737011902039.png" /></span></P><P>Select a customizing request or create a new one and continue<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_0-1737012839684.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212966i3CA5F8387C15CB11/image-size/medium?v=v2&px=400" role="button" title="RajatArora_0-1737012839684.png" alt="RajatArora_0-1737012839684.png" /></span></P><P>Service group has been published<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_10-1737012014371.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212961i5F5D8F07E7683B81/image-size/medium?v=v2&px=400" role="button" title="RajatArora_10-1737012014371.png" alt="RajatArora_10-1737012014371.png" /></span></P><P>Once published, service group will be visible under service groups on v4 admin<BR /><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_11-1737012102829.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212963i387BD23946CAD7EC/image-size/medium?v=v2&px=400" role="button" title="RajatArora_11-1737012102829.png" alt="RajatArora_11-1737012102829.png" /></span></P><P>Now, go back to eclipse and refresh (F5) the service binding. <EM><STRONG>Voila! </STRONG></EM>Now, the service has been published, and the entity set and service URL will be visible<EM><BR /></EM><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="RajatArora_12-1737012153171.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/212964i6D2D33D32214CDC6/image-size/medium?v=v2&px=400" role="button" title="RajatArora_12-1737012153171.png" alt="RajatArora_12-1737012153171.png" /></span></P><P>Thanks for going through the blog and now you will be able to publish any v4 service. <span class="lia-unicode-emoji" title=":grinning_face:">😀</span></P><P> </P>2025-01-21T19:02:11.234000+01:00https://community.sap.com/t5/technology-blogs-by-members/rap-draft-actions/ba-p/13988688RAP Draft Actions2025-01-21T19:39:15.365000+01:00Nayanakumarhttps://community.sap.com/t5/user/viewprofilepage/user-id/1490076<P>Draft actions in the ABAP RESTful Application Programming (RAP) model are used to handle temporary versions of business objects before they are saved as active versions.</P><P>Here are some key points about draft actions in RAP:<BR />Draft Actions: These include Edit, Activate, Discard, and Resume. They allow data manipulation on the RAP draft table.<BR />Behavior Definition: Draft actions must be specified in the behavior definition of the business object. This ensures that the draft handling is enabled.<BR />Implementation: While RAP provides default implementations for these actions, you can customize them as needed. For example, you might want to control which fields can be edited or how data is validated</P><P>Draft Action Edit<BR />The draft action EDIT copies an active instance to the draft database table. Feature and authorization control is available for the EDIT, which you can optionally define to restrict the usage of the action.</P><P> </P><P>Draft Action Activate<BR />The draft action ACTIVATE is the inverse action to EDIT. It invokes the PREPARE and a modify call containing all the changes for the active instance in case of an edit-draft, or a CREATE in case of a new-draft. Once the active instance is successfully created, the draft instance is discarded.</P><P>In contrast to the draft action Edit, the Activate does not allow feature or authorization control. Authorization is not available as the Activate only transfers the state of the draft buffer to the active buffer. Authorization is controlled when the active instance is saved to the database.</P><P> </P><P>The draft action activate is also available in an optimized variant which can improve the performance compared to the variant without optimization.</P><P> </P><P>Draft Action Discard<BR />The draft action DISCARD deletes the draft instance from the draft database table. No feature or authorization control can be implemented.</P><P> </P><P>Draft Determine Action Prepare<BR />The draft determine action PREPARE executes the determinations and validations that are specified for it in the behavior definition. The PREPARE enables validating draft data before the transition to active data.</P><P>In the behavior definition, you must specify which determinations and validations are called during the prepare action. Only determinations and validations that are defined and implemented for the BO can be used.</P><P>Note<BR />For performance reasons, determinations and validations are not executed during the draft determine action Prepare, if these determinations and validations have already been executed during a previous determine action that has been executed on the instance in the same transaction.</P><P>This performance optimization is not applied in the following cases:</P><P>A modification performed after the first determine action triggers a determination/validation.</P><P>A validation in the first determine action reports a failed key.</P><P>A determination/validation has been assigned using the addition always.</P><P>In order to ensure data consistency, make sure that your determinations and validations follow the respective modelling guidelines described in Determination and Validation Modelling.</P><P> </P><P>Draft Action Resume<BR />The draft action RESUME is executed when a user continues to work on a draft instance whose exclusive lock for the active data has already expired. It recreates the lock for the corresponding instance on the active database table. On a Fiori Elements UI, it is invoked when reopening and changing a draft instance whose exclusive lock is expired.</P><P>In case of a new draft, the same feature and authorization control is executed as defined for a CREATE. In case of an edit-draft, the same feature and authorization control is executed like in an Edit.</P><P>It is sequence of triggering when edit is done in Draft.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_3-1737106074734.png" style="width: 547px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213420i86EE36A1A62B966A/image-dimensions/547x234?v=v2" width="547" height="234" role="button" title="Nayanakumar_3-1737106074734.png" alt="Nayanakumar_3-1737106074734.png" /></span></P><P> </P><P> </P><P> </P><P>In the Behavior define the draft actions </P><P> </P><pre class="lia-code-sample language-abap"><code>managed implementation in class ZBP_R_NP_DT_PARTNER unique;
strict ( 2 );
with draft;
define behavior for ZR_NP_DT_PARTNER alias ZrNpDtPartner
persistent table znp_dt_partner
draft table znp_dt_partner_d
etag master LastChangedAt
lock master total etag LastChangedAt
authorization master ( global )
{
field ( mandatory : create )
Partner;
field ( readonly )
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt;
field ( readonly : update )
Partner;
create;
update;
delete;
validation city on save { field City; create; }
validation currency on save { field PaymentCurrency; create; update; }
draft action Activate optimized with additional implementation;
draft action Discard with additional implementation;
draft action Edit with additional implementation;
draft action Resume with additional implementation;
draft determine action Prepare
{
validation City;
validation currency;
}
mapping for znp_dt_partner
{
Partner = partner;
Name = name;
Street = street;
City = city;
Country = country;
PaymentCurrency = payment_currency;
CreatedBy = created_by;
CreatedAt = created_at;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}
}</code></pre><P> </P><P>Projection view Behavior Definition.</P><P> </P><pre class="lia-code-sample language-abap"><code>projection implementation in class ZBP_C_NP_DT_PARTNER unique;
strict ( 2 );
use draft;
define behavior for ZC_NP_DT_PARTNER alias ZcNpDtPartner
use etag
{
use create;
use update;
use delete;
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
}</code></pre><P> </P><P> </P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_0-1737105605715.png" style="width: 551px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213416iEE5D70CAB4E36310/image-dimensions/551x270?v=v2" width="551" height="270" role="button" title="Nayanakumar_0-1737105605715.png" alt="Nayanakumar_0-1737105605715.png" /></span></P><DIV class=""> </DIV><P>In the draft table the field value will be null hence it is not valid.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_2-1737105795922.png" style="width: 550px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213418i8F17F16DF7C8F04F/image-dimensions/550x279?v=v2" width="550" height="279" role="button" title="Nayanakumar_2-1737105795922.png" alt="Nayanakumar_2-1737105795922.png" /></span></P><P> </P><P>If we provide the value and save it will be updated to active instance and that record will be discard from the draft.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_1-1737102437148.png" style="width: 560px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213391i52D28CE002505A16/image-dimensions/560x151?v=v2" width="560" height="151" role="button" title="Nayanakumar_1-1737102437148.png" alt="Nayanakumar_1-1737102437148.png" /></span></P><P> </P><P> </P><P>Once we add the valid value it will saved to active instance and removed from Draft.</P><P>Database table.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_2-1737102458188.png" style="width: 561px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213392i4071E597748C1C75/image-dimensions/561x233?v=v2" width="561" height="233" role="button" title="Nayanakumar_2-1737102458188.png" alt="Nayanakumar_2-1737102458188.png" /></span></P><P>Draft table.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Nayanakumar_3-1737102516101.png" style="width: 522px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/213393i4C74305B9CC04AD8/image-dimensions/522x269?v=v2" width="522" height="269" role="button" title="Nayanakumar_3-1737102516101.png" alt="Nayanakumar_3-1737102516101.png" /></span></P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P><P> </P>2025-01-21T19:39:15.365000+01:00