RAP Actions: Automatic Background Job With Static Factory Actions

In one of our recent projects, we implemented a requirement in an SAP S/4HANA Public Cloud environment to automatically create a business object once specific conditions in a job table were fulfilled. We executed the creation process on a defined date through background processing.

For scenarios like this, the ABAP RESTful Application Programming Model (RAP) offers a powerful concept: factory actions. While they may appear simple at first glance, they reveal their true strength when applied to real-world business requirements.

In this article, we take a closer look at RAP actions in general, explain how to implement a static factory action, and demonstrate how to model such scenarios in a clean and efficient way.

Type of RAP Actions: The little Fairies

Before we talk about actions, we should first define what RAP actions actually are. When thinking about an action, imagine a little fairy performing the magic behind the scenes in a RAP application. That magic could be anything from saving data to copying or triggering specific business operations.

As shown in the table below, RAP provides three different types of actions to choose from: Instance Action, Static Action, and Factory Action. However, developers must understand which type of action fits which scenario to design clean and maintainable applications. Consider the decision diagram below and the table, which provide a quick guideline on when to use each type of RAP action.

Type of ActionBound to InstanceCreates DataInput ParametersTypical Use CaseExample
Instance Action✅ Yes❌ NoOptionalChange state of an existing objectApprove Sales Order
Static Action❌ No❌ UsuallyOptionalGlobal operation (not tied to instance)Mass recalculation
Factory Action❌ (static)✅ YesUsually RequiredCreate new business objectsCreate Submission / Template

An action represents a dedicated operation on a CDS entity. These operations can handle changes either internally within the application logic or externally through integrations and APIs. What all action types have in common is their overall implementation flow, which follows the same fundamental pattern (described throughout this blog):

  1. Define in BDEF: Specify the action name in the behavior definition file.
  2. Implement in ABAP: Write the logic in the corresponding behavior pool class using the FOR MODIFY addition.
  3. Consume in UI: Expose the action in the UI service projection layer to create buttons in SAP Fiori Elements apps.
  4. Trigger via EML: Use MODIFY ENTITIES to invoke the action in code

When the requirement is to create new business object instances with predefined default values or parameterized input — without relying on an already existing instance — static factory actions become particularly relevant. Unlike standard CREATE operations, factory actions provide a dedicated hook for custom logic to define and prepare the initial state of the new business object before it is persisted.

RAP Action: Which action to be taken when
RAP Action: Which action to be taken when

In our scenario, the factory action in RAP provided exactly the required flexibility: the ability to create a new business object instance based on existing data and predefined business conditions. The practical scenario below was divided into three main implementation steps:

  • Implementing the caller class for the job
  • Enhance the existing Behaviour Implementation and Implement the method for the action
  • Perform the basic Job maintenance, like Catalog, Template, and IAM

The Job Caller Class for the RAP action

The caller class contains a method that determines whether the application should trigger the creation of the business object. Another method checks whether today’s date matches the date maintained in the ZSE_JOBDetails table.

The actual logic, however, is executed in the create_submission_dp_template action, which is triggered via the MODIFY ENTITIES statement.

Wherever necessary, the application raises meaningful error messages and logs them through a framework built on top of the standard ABAP Application Jobs (APJ) runtime. The framework follows a self-healing approach and automatically retries the process whenever failures occur.

CLASS zcl_subm_create_bo DEFINITION
PUBLIC
INHERITING FROM zcl_job_fw_base
FINAL
 
CREATE PUBLIC .
PUBLIC SECTION.
METHODS zif_job_fw~process REDEFINITION.
 
PRIVATE SECTION.
CONSTANTS job_case TYPE zsdp_e_jobcase VALUE 'ABO’.
 
METHODS process
RAISING zcx_subm_create_bo cx_apj_rt_content
cx_bali_runtime.
 
"! <p class="shorttext synchronized" lang="en">The purpose of this method is to determine if today's day matches one of the
"! dates maintained in the Job Details table for the job case "ABO“.</p>
"!
"! @parameter result | <p class="shorttext synchronized" lang="en">Result of the determination</p>
METHODS check_run_today
RETURNING
VALUE(result) TYPE abap_bool.
 
ENDCLASS.

 
CLASS zcl_subm_create_bo IMPLEMENTATION.
 
METHOD zif_job_fw~process.
  process( ).
 
ENDMETHOD.
 

METHOD check_run_today.
 
  DATA(todays_date) = cl_abap_context_info=>get_system_date( ).
  result = abap_true.
  
  SELECT SINGLE job_case FROM ZSE_JOBDetails
  WHERE job_case = @job_case
  AND Available_date = @todays_date
  INTO @DATA(job_detail).
 
  IF sy-subrc <> 0.
    result = abap_false.
  ENDIF.
 
ENDMETHOD.
 
METHOD process.
 
  IF NOT check_run_today( ).
    log_warning( |Automatic Creation of Business Object Template not scheduled for today| ).
    RETURN.
  ENDIF.
  
 
  " ------------------------------------------------------------------------
  " Create new BO template
  " ------------------------------------------------------------------------
  MODIFY ENTITIES OF zsubm_re_confh
  ENTITY SubHeader
  EXECUTE create_submission_dp_template AUTO FILL CID
  WITH VALUE #( ( %cid = 'My%CID' ) )
  MAPPED FINAL(mapped_items)
  REPORTED FINAL(reported_items)
  FAILED FINAL(failed_items).
  
 
  IF failed_items IS NOT INITIAL AND reported_items IS NOT INITIAL.
    DATA(errordetails) = conv string( reported_items-subheader[ 1 ]-%msg->if_t100_dyn_msg~msgv1 ).
    log_error( |Automatic Creation of Business Object failed due to following error: { errordetails }| ).
    RAISE EXCEPTION TYPE zcx_subm_create_bo
    EXPORTING
      textid = zcx_subm_create_bo=>failed_creation_w_errordetails
      message = errordetails.
  ENDIF.
   
  " ------------------------------------------------------------------------
  " Create new Market Groups for DP template
  " ------------------------------------------------------------------------
  DATA tmpl_mg_create TYPE TABLE FOR ACTION IMPORT zsubm_re_confh\\SubHeader~create_all_mg.
   
  LOOP AT mapped_items-subheader ASSIGNING FIELD-SYMBOL(<mapped_item>).
   
  tmpl_mg_create = VALUE #( 
  ( %cid_ref = <mapped_item>-%cid
    demandplanid = <mapped_item>-DemandPlanID )
  ).
  
 
  MODIFY ENTITIES OF zsubm_re_confh
  ENTITY SubHeader
  EXECUTE create_all_mg FROM tmpl_mg_create
  REPORTED FINAL(reported_mg_items)
  FAILED FINAL(failed_mg_items).
  
 
  IF failed_mg_items IS NOT INITIAL.
    log_error( |Automatic Creation of Business Object failed during creation of Market Groups| ).
    RAISE EXCEPTION TYPE zcx_subm_create_bo
      EXPORTING
      textid = zcx_subm_create_bo=>failed_creation_with_mg.
  ENDIF.
  
 
  ENDLOOP.
  
 
  " ------------------------------------------------------------------------
  " save sequence of managed scenario
  " ------------------------------------------------------------------------
  COMMIT ENTITIES
  RESPONSE OF zsubm_re_confh
  FAILED FINAL(failed_commit_item)
  REPORTED FINAL(reported_set).
  
 
  IF sy-subrc <> 0.
    log_error( |Automatic Creation of Business Object Template failed for month { xco_cp=>sy->date( )->month }| ).
    RAISE EXCEPTION TYPE zcx_subm_create_bo
      EXPORTING
      textid = zcx_subm_create_bo=>failed_creation_auto_bo.
  ENDIF.
   
  log_success( |Automatic Creation of Business Object Template processed successfully for month { xco_cp=>sy->date( )->month }| ).
   
ENDMETHOD.
ENDCLASS.

Enhance the Behaviour Definition

We declared the previously mentioned action in the behavior definition (BDEF) of the corresponding business object. We then added the method to the local handler class of the business object entity in the behavior pool using the quick fix functionality.

// Create a Business Object Template via job
static factory action create_submission_dp_template [1];

The implementation of the action method resulted in the following approach: first, we defined the initial values for the new business object in the template_create structure. These values are then passed to the MODIFY ENTITIES OF statement, which handles the actual creation process.

CLASS lhc_subheader DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
...
METHODS create_submission_dp_template FOR MODIFY
IMPORTING keys FOR ACTION subheader~create_submission_dp_template.
...
ENDCLASS.
 
CLASS lhc_subheader IMPLEMENTATION.
...
 
METHOD create_submission_dp_template.
 
  TRY.
 
    FINAL(planversion) = 1.
    FINAL(planid) = cl_system_uuid=>create_uuid_x16_static( ).
    FINAL(current_cycle_id) = cycle_object->get_active_planning_cycle( ).
    TYPES ty_create_tab TYPE TABLE FOR CREATE zsubm_re_confh\\SubHeader.
 
    
    DATA(template_create) = VALUE ty_create_tab(
    ( planid = planid
      planversion = planversion
      PlanCycle = current_cycle_id
    ) ).
 
    
    MODIFY ENTITIES OF zsubm_re_confh IN LOCAL MODE
    ENTITY subheader
    CREATE FIELDS ( planid planversion PlanCycle PlanName )
    WITH template_create
    MAPPED FINAL(mapped_items)
    REPORTED FINAL(reported_items)
    FAILED FINAL(failed_items).
     
    mapped = mapped_items.
    failed = failed_items.
   
  CATCH zcx_planning_cycle_error cx_uuid_error INTO DATA(exception).
 
    APPEND VALUE #( %cid = '%cid' ) TO failed-subheader.
    APPEND VALUE #(
      %cid = '%cid'
      %msg = new_message(
        id = 'ZSUBMISSION'
        number = '020'
        severity = if_abap_behv_message=>severity-error
        v1 = |{ exception->get_text( ) }|
      )
    ) TO reported-subheader.
 
  ENDTRY.
ENDMETHOD.
ENDCLASS.

To run this logic as part of a batch job in S/4HANA Public Cloud, developers first need to complete some customising in ABAP Development Tools (ADT), which consists of following steps:

  1. Job Catalog element: The Job Catalog contains the executable class, which in our scenario is class zcl_subm_create_bo.
  2. Job Template element: Next, developers create a Job Template element in ADT that references the catalog. As a useful side effect, developers can already use the template to trigger the logic and test the program.
  3. Business Catalog IAM: Finally, developers create the “Business Catalog IAM” element. This step makes the template searchable in the SAP BTP Application Jobs app and allows the system to execute the logic as a scheduled job.

And as one of the very last step, you can schedule your job in BTP “SAP Job Scheduling Service”.

Some Final Words

In this article, we explored the concept of RAP actions with a particular focus on static factory actions in SAP S/4HANA Public Cloud scenarios. Using a real-world background job requirement, we demonstrated how RAP enables developers to create business object instances dynamically based on predefined business conditions and scheduled execution dates.

We explained the different action types available in RAP, highlighted when developers should use each type, and illustrated the common implementation flow shared across all actions. We also showed how developers declare and implement actions within the behavior definition and behavior pool of a business object.

Finally, we demonstrated how factory actions provide a clean, extensible, and maintainable approach for modeling automated creation processes in RAP applications, especially in cloud-centric and clean-core compliant architectures.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top