Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
RavdeepSingh
Explorer
19,570

From User Exits to RAP: Adopting a Clean Core Approach in S/4HANA

Welcome to our SAP blog! In this blog we’re diving into the world of Clean Core in S/4HANA and how you can achieve it using the ABAP RESTful Application Programming Model (RAP). If you’re looking to future-proof your SAP system while extending its functionalities seamlessly, you’re in the right place. Let’s explore how RAP can help you maintain a cloud-ready, upgrade-safe system without compromising on flexibility.

 

Why Clean Core Matters

In today’s fast-paced digital landscape, businesses need agile and scalable systems. Clean Core is all about keeping your SAP system lean, efficient, and ready for the cloud. It ensures that your customizations don’t interfere with SAP’s standard processes, making upgrades smoother and reducing technical debt.

But here’s the challenge: How do you extend standard functionalities without breaking the core? Traditional methods like User Exits and BAdIs have served us well, but they’re not always cloud-compliant. Enter RAP a modern, event-driven approach to building and extending applications in S/4HANA starting from 2022.

 

Real-World Insights: The Shift to RAP

Through numerous customer engagements, my colleague Balaji @Balaji_Guptha  and I have seen firsthand the challenges of implementing Clean Core. Whether it’s a Brownfield migration or a Greenfield implementation, the goal remains the same: extend without breaking.

While traditional enhancements like User Exits are familiar, they often lead to upgrade headaches. RAP, on the other hand, offers a fresh perspective. It allows you to extend standard processes without modifying the core, ensuring compatibility with future upgrades.

 

The Power of Event-Driven Architecture

At the heart of RAP lies Event-Driven Architecture (EDA). This approach enables systems to react to changes in real-time, making it ideal for modern business processes. With RAP, you can leverage business events to trigger actions, integrate systems, and automate workflows—all while keeping your core clean.

Key Use Cases for RAP Events:

  • Real-Time Notifications: Automatically notify external systems about critical changes, like a new Sales Order or a status update.
  • Seamless System Integration: Enable third-party applications to react to business events without constant polling or synchronous API calls.

RAP Business Event Consumption

SAP provides two approaches to consuming RAP business events:

  1. Remote Event Consumption: Events consumed by external systems (e.g., SAP Event Mesh).
  2. Local Event Consumption: Events handled within the same RAP-based application without external dependencies.

This blog focuses on Local Event Consumption, which enhances system responsiveness and automation within an S/4HANA system.

Local Event Consumption: A Game-Changer

One of the most powerful features of RAP is Local Event Consumption. This allows you to handle events within the same RAP-based application, eliminating the need for external middleware. It’s perfect for scenarios where immediate follow-up actions are required.

How It Works:

  1. Event is Triggered: A change occurs in a RAP business object (e.g., Sales Order creation).
  2. Local Event Handling: An event handler class within the same application processes the event.
  3. Business Logic Execution: The handler class executes predefined logic, such as updating related entities or triggering validations.

Identifying the Standard RAP BO for Business Events

Before implementing local event consumption, identifying the correct RAP Business Object (BO) Root Entity is essential. Follow these steps:

 

  • Select your SAP product (e.g., S/4HANA Cloud, Private Edition)RavdeepSingh_1-1738847877038.png

 

  • Locate On-Stack Extensibility → Business Object InterfaceRavdeepSingh_2-1738847925047.png

 

  • Search for the relevant Business Object, e.g., Sales OrderRavdeepSingh_3-1738847925055.png

     

    RavdeepSingh_4-1738847925067.png

     

  • Once the Business Object (BO) Interface Name is identified, the next step is to navigate to Eclipse ADT (ABAP Development Tools) to determine the Event Binding and Root View Entity Name required for implementing local event consumption in RAP.
  • In Eclipse open the behavior definition for the Business Object interface I_SALESORDERTP.

    RavdeepSingh_5-1738847925081.png

     

  • In the ABAP repository tree navigate to Business Service Folder to get the Event binding name for the Business Object Interface I_SALESORDERTP.RavdeepSingh_6-1738847925090.png

     

  • Select the required business event, in our case it is Sales Order Created event.

    In the event binding we can find the standard RAP business object with events, R_SALESORDERTP.

    RavdeepSingh_7-1738847925102.png

     

  • Next navigate to the behavior definition of R_SALESORDERTP business object to check the events enabled for the RAP BO.RavdeepSingh_8-1738847925123.png

     

Identifying Business Events

SAP Provides a standardized way to explore and utilize business events through the SAP Business Accelerator Hub. This platform allows developers and architects to identify events relevant to their business processes and integrate them into an event-driven architecture.

To find the required business event, follow these steps:

  1. Navigate to SAP Business Accelerator Hub 
  2. Select the relevant SAP product (e.g., SAP S/4HANA Cloud, SAP S/4HANA Cloud Private Edition) based on the system you are working with.RavdeepSingh_3-1738852206372.png
  3. Once the product is selected, navigate to the "Events" tab. This section provides a list of all available events that the selected SAP solution can trigger. Search for the business process or required event in the search bar. In this example we have considered Sales Order EventsRavdeepSingh_4-1738852285924.png
  4. Select the event and click on it to view the detailed information.RavdeepSingh_5-1738852408142.png

Use Case: Automating Delivery Block in Sales Orders

Let’s look at a real-world scenario where RAP’s Local Event Consumption shines.

Business RequirementWhen a Sales Order is created, the system should automatically apply a delivery block if certain conditions are met. These conditions are based on predefined rules stored in a custom table.

Traditional ApproachIn the past, this would be implemented using a User Exit (MV45AFZZ). However, this approach is not cloud-compliant and can lead to upgrade challenges.

Clean Core Approach with RAPUsing RAP’s Local Event Consumption, we can achieve the same functionality without modifying the core. Here’s how:

Creating an Event Handler Class
  1. Define a global class that listens for events from the Sales Order business object.
  2. Use the keyword FOR EVENTS OF to specify the behavior definition.RavdeepSingh_0-1738849311476.png
Inherit from the Event Handler Superclass
  1. In the local class, inherit from CL_ABAP_BEHAVIOR_EVENT_HANDLER to access event-handling capabilities.RavdeepSingh_1-1738849311480.png
Define Event Handling Methods
  1. Create methods to handle specific events, such as SalesOrder.Created.RavdeepSingh_2-1738849311486.png
  2. Category of the custom class created will be ‘Event Handler for Entity Events’.RavdeepSingh_3-1738849311497.png
Implement Business Logic
  1. Logic to enable the delivery block at sales order header level.
  2. In this implementation, the Enablement of the Delivery Block in the sales order is achieved using Entity Manipulation Language (EML) instead of traditional BAPIs. 
  3. Refer to the SAP Help Portal at the following link: https://help.sap.com/docs/abap-cloud/abap-rap/entity-manipulation-language-eml . This resource provides the syntax and detailed explanation for EML.RavdeepSingh_4-1738849311506.png

By implementing this, we successfully automated the application of a delivery block in a cloud-compliant manner, ensuring minimal technical debt and future-proof extensibility. This approach not only aligns with SAP’s Clean Core principles but also enhances system agility and maintainability.

 

Why This Matters

By adopting RAP’s Local Event Consumption, you’re not just solving a business problem—you’re future-proofing your SAP system. This approach ensures that your customizations are cloud-compliant, upgrade-safe, and scalable.

 

Final Thoughts

RAP is more than just a programming model—it’s a mindset shift. It encourages us to rethink how we extend SAP systems, moving away from traditional methods and embracing modern, event-driven architectures. Whether you’re dealing with Sales Orders, Purchase Orders, or any other business process, RAP provides the tools you need to keep your core clean and your business agile. So, what are you waiting for? Start exploring RAP today and unlock the full potential of your S/4HANA system!

Stay tuned for more insights on Clean Core strategies in S/4HANA!

Feel free to ask for any clarifications or share your suggestions!

Regards,

Ravdeep Singh 

23 Comments
satanik09
Discoverer

Excellent blog and this is really helpful for clean core projects!

Manikandan
Newcomer
0 Kudos

Wonderful blog. @RavdeepSingh 

babu4abap
Explorer

Thank you @RavdeepSingh  & @Balaji_Guptha for the detailed explanation. This will be very helpful to many people.

rammel_sapdev
Participant
0 Kudos

Hi, did you create the event handler class under a Standard ABAP package or ABAP Cloud Package? Is it still considered as clean core even though we created the class under the Standard ABAP package? 

@Andre_Fischer , any thoughts?

Sabarim_07
Explorer
0 Kudos

Hi @RavdeepSingh ,

Whether this event will trigger via GUI t-code(va01) or it is not possible for GUI t-code.

Whether this event will trigger only when we use the respective RAP based fiori app where the Event is declared 

Please suggest.

Thanks 

rammel_sapdev
Participant
0 Kudos

I think it will trigger from both. You can do a where-used of the event in the RAP BO. Another way to check is to implement the event handler class and maybe have a breakpoint.

Sabarim_07
Explorer
0 Kudos

Hi @Ramnnk ,

I have tried it. it didn't trigger via GUI.

Thanks

RavdeepSingh
Explorer

Hi @rammel_sapdev   Thanks for your query.

If I understand correctly, you're asking whether the event handler class "ycl_salesorder_event_consump" was created under a Standard ABAP package or an ABAP Cloud package. We created it under a Standard ABAP package since we worked in an On-Premise system. However, it should also be possible to create it under an ABAP Cloud package in Cloud system, though we haven't tried it yet.

For reference, the standard RAP BO R_SALESORDERTP is also developed under a Standard ABAP package in On-Premise. Additionally, based on my understanding of Extensibility, RAP is considered Clean Core, so this should also fall under the Clean Core approach.

Balaji_Guptha
Explorer
0 Kudos

Hello @Sabarim_07 ,

Yes, it is possible to trigger events through GUI as well as FIORI Apps.
Could you explain the steps you followed to trigger the event ?.

DiegoValdivia
Active Participant
0 Kudos

Thanks for this great post.

RAP Local events is a very powerful tool that can help us leveraging situations where there's not a suitable Badi or when the client doesn't want to pay for Even Mesh.

Though, as per my experience, there's a big indirect flaw in RAP Local events related to S/4HANA Cloud Public Edition. The problem is that we can save logs using CL_BALI_LOG_DB but there's no App to display those logs, which doesn't make any sense at all. We can see SAP's reply on the following Question I created on the community: https://community.sap.com/t5/general-and-cross-topics-q-a/is-it-possible-to-display-custom-applicati... 

We have used tcode SLG1 for decades to display our program logs, but now, in Cloud Public, because of some manager's decision, suddenly we can't. Man, that's so frustrating.

gferdebar
Explorer
0 Kudos

Hi,

How to handle case when sales order is locked and we are not eable to update sales order in moment of event triggering?

 

Jawad_Shaikh
Discoverer
0 Kudos

Thanks for the detailed explanation @RavdeepSingh 

Jyotheesh_7
Newcomer
0 Kudos

Thank you for the detailed explanation @RavdeepSingh ....

roger_sainsbury
Product and Topic Expert
Product and Topic Expert

Hi Ravdeep,

this is an interesting approach and kudos to you for figuring it out and sharing it.

However I share @rammel_sapdev 's concern. It's not possible to create the event handler class in ABAP Cloud, because the R_* Business Objects are not released for ABAP Cloud development. As I understand it, they are not intended for customer use. E.g. see here:

Although technically possible, a Business Object should not be consumed directly. Instead, consumers should access Business Object Projections (BO Projections) and Business Object Interfaces (BO Interfaces)

It's the BO Interface, I_SALESORDERTP, that you initially identify - but we can't use this, because it doesn't include the events.

So sorry to say, I don't think this approach is Clean Core.

RavdeepSingh
Explorer
0 Kudos

Hi roger_sainsbury,

Thank you for your feedback and for sharing this perspective. I agree that in ABAP Cloud, the recommended approach is to use Business Object Projections and Interfaces rather than directly consuming R_* Business Objects.

The objective of my blog was to explore an alternative approach where, instead of relying on classic User Exits, we leverage RAP and event handling to achieve similar extensibility. While this method demonstrates what is technically possible, I understand the concerns regarding its alignment with SAP’s guidelines. However, it still represents a shift from classical ABAP towards adopting the RAP framework.

Currently, although RAP events are available in cloud systems, they remain under the standard ABAP package rather than a dedicated Cloud package. Based on this understanding, local event consumption is currently feasible in on-premise environments. However, as RAP continues to evolve, SAP may extend this capability to Cloud as well, aligning with its focus on event-driven architecture.  

Thanks!

Sabarim_07
Explorer
0 Kudos

Hi @RavdeepSingh / @Balaji_Guptha ,
Thanks for the blog. We are in S4HANA 2023 Private cloud, I have implemented the Event Consumption model for the outbound delivery. Activated the event in SWEC and SWETYPV tcode. 

When we post the PGI, how to trigger the local event consumption model class ? Whether it will not trigger for GUI tcode like VL02N or it will trigger only for the RAP events. Please suggest.

Thanks,

chrisjsosa
Explorer
0 Kudos

Hello @roger_sainsbury, is there an alternative to achieve the business requirement from @RavdeepSingh that is cleaner than using the RAP Events suggested? Implementing the User Exit MV45AFZZ?

Many thanks and kind regards,

Christian

chetan717
Newcomer
0 Kudos

l

MLogunov
Associate
Associate

a very nice blog.

there is also another way to filter Created event for delivery block via managed event and raise a custom event for specific delivery block reason value. Pay attention, during behavior definition extension we are not using I_SALESORDERTP interface:

 

1.Filter CDS for new custom event

@EndUserText.label: 'Sales Order Created With Filter'

@event: {

   description: 'Sales Order Created with FIlter',

   sapObjectNodeType: 'SalesOrder',

   implementedBy    : ['ABAP:RAP_EVENT']

}

@vdm.usage.type: [#EVENT_SIGNATURE]

define abstract entity ZZ_D_SALESORDERCREATEDFILTERED  {

           @event.raisedAt.dateTime: true

        EventRaisedDateTime               : vdm_lastchangedon;

        SO                                : vbeln;

        SOType                            : auart_unv;

        SalseOrganization                 : vkorg;

        DistributionChannel               : vtweg;

        OrganizationDivision              : spart;

        SoldToParty                       : kunnr;

/*        @event.context.attribute: ''     */

        DeliveryBlockReason               : lifsk; 

}

 

2 Parameter entity for managed Event

@AbapCatalog.viewEnhancementCategory: [#NONE]

@AccessControl.authorizationCheck: #NOT_REQUIRED

@EndUserText.label: 'Sales'

@Metadata.ignorePropagatedAnnotations: true

@ObjectModel.usageType:{

    serviceQuality: #X,

    sizeCategory: #S,

    dataClass: #MIXED

}

define view entity ZZ_D_SalesOrderF as select from I_SalesOrder

{

    key SalesOrder,

        SalesOrderType,

        SalesOrganization,

        DistributionChannel,

        OrganizationDivision,

        SoldToParty,

        DeliveryBlockReason       // Filtering this field

 }

 

3. Behavior Definition Extension

     extension;

   // using interface I_SALESORDERTP;                --Not used for event Created visibility

    //

    // implementation in class zbp_salesordertp_event unique;  --Not used for global BD class

    //                                                         --instead we  have a global abstract

    //                                                         --class for Events zcl_so_event_handler

 

    extend behavior for SalesOrder

    {

    event Z_CreatedWithFilter parameter ZZ_D_SALESORDERCREATEDfiltered;   //Custom event

    managed event Z_Derived_Created on Created parameter ZZ_D_SalesOrderF;

 

    }

4. Global class for events

CLASS zcl_so_events_handler DEFINITION

  PUBLIC

  ABSTRACT                        "Abstract definition

  FINAL

  FOR EVENTS OF R_SalesOrderTP.   "Local class is defined

 

  PUBLIC SECTION.

  PROTECTED SECTION.

  PRIVATE SECTION.

ENDCLASS.

 

 

 

CLASS zcl_so_events_handler IMPLEMENTATION.

ENDCLASS.

 

 

5. Local Class in (4)

CLASS lcl_so_events_handler DEFINITION INHERITING FROM cl_abap_behavior_event_handler.

  PRIVATE SECTION.

    METHODS filter_event_create FOR ENTITY EVENT created_instance FOR SalesOrder~Z_Derived_Created.

ENDCLASS.

CLASS lcl_so_events_handler IMPLEMENTATION.

  METHOD filter_event_create.

    cl_abap_tx=>save( ).

 

    IF created_instance IS NOT INITIAL.

      RAISE ENTITY EVENT R_SalesOrderTP~Z_CreatedWithFilter

        FROM VALUE #(

          FOR <so> IN created_instance (

            so = <so>-SalesOrder

            SOType = <so>-SalesOrderType

            SalseOrganization = <so>-SalesOrganization

            DistributionChannel = <so>-DistributionChannel

            SoldToParty = <so>-SoldToParty

            DeliveryBlockReason = <so>-DeliveryBlockReason   "Here we can have a filer value

          )

        ).

    ENDIF.

 

  ENDMETHOD.

ENDCLASS.

RavdeepSingh
Explorer
0 Kudos

Hello @MLogunov,

Thank you for your insightful comment. This approach certainly adds another dimension to handling business scenarios where event-based filtering is required. 

Thanks again for your valuable contribution.

zPC
Explorer
0 Kudos

Thank you for sharing your insights on transitioning from user exits to RAP with a Clean Core approach. I found your example with the Local Event Consumption class quite interesting.

However, I'm curious about the dependency on R_SalesOrderTP for the event consumption. As I understand it, this restricted layer might not align fully with the Clean Core principles, due to the lack of a C1 Contract for Cloud Development.

Ideally, for true Clean Core extensibility, wouldn't local event consumption be more appropriate within the I_SalesOrderTP interface layer, using developer extensibility? Specifically, the addition of a "USE EVENT" command within I_SalesOrderTP would allow us to subscribe to SAP Standard RAP BO events in a Clean Core way. It seems like this would provide a more stable and future-proof solution.

Based on my understanding, it appears that, at least for S/4HANA PCE 2023, there might not be a viable Clean Core solution for local event consumption of SAP Standard RAP BO events.

I hope that in the next S/4HANA PCE version, SAP will expose the events in the Standard RAP BO Interface layer (I_*TP). This would greatly enable Clean Core development and streamline event-driven extensions.

Perhaps I'm misunderstanding something, and I'd appreciate your thoughts on this. Thank you again for the informative post.

Sunngupt
Discoverer
0 Kudos

Lots of information in single blog.  Very well written @Balaji_Guptha  and @RavdeepSingh 

mamic
Discoverer
0 Kudos

@RavdeepSingh : It's very interesting. Thanks for sharing. 

I'm trying to recreate this, but my event consumption class isn't triggered, so my own coding in the method with FOR ENTITY EVENT created FOR SalesOrder~created, when I create a sales order with EML (R_SalesOrderTP, salesorder). The sales order creation with EML is succesfull

Do I have to register something, the global class with the local class or else? I don't get it, how the framework understands, when it has to trigger the coding in the y-class.

Maybe you could describe this in more detail of your blog, please. I realy would like to know. 

Labels in this area