Handling Cross Business Object Transactions in RAP Using Actions
Share

[[{“value”:”

Introduction

In the SAP RAP, most examples focus on single Business Object (BO) operations. However, real-world enterprise applications rarely operate in isolation. A single business transaction often impacts multiple BOs—for example, creating a Delivery should trigger Billing, updating inventory, and possibly financial postings.
In this blog, we explore how to implement cross-BO interaction using RAP Actions, where:

  • A Delivery BO triggers creation in a Billing BO
  • Both operations are executed within the same LUW (Logical Unit of Work)
  • Data consistency is preserved using RAP’s transactional buffer

Business Scenario

Consider a typical Order-to-Cash process:

  1. A Delivery is created for a customer.
  2. Once the delivery is confirmed, a Billing document must be generated.
  3. The system should:
    • Automatically create a Billing record
    • Update the Delivery status to DELIVERED
    • Ensure both operations succeed or fail together

Implementation Steps

STEP 1: Create a Data base Table 

Data base  table For Delivery Details  

@EndUserText.label : ‘delivery details’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zte_t_delivery_s {
key delivery_id : abap.char(10) not null;
customer_id : abap.char(5);
material : abap.char(20);
price : abap.char(10);
delivery_date : abap.dats;
delivery_status : abap.char(15);
}

Data Base table for Billing Details

@EndUserText.label : ‘Billing Details’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zte_t_billing_s {
key billing_id : abap.char(10) not null;
customer_id : abap.char(5);
delivery_id : abap.char(10);
material : abap.char(20);
price : abap.char(10);
}

STEP 2: Create root CDS views for both tables

Root view For Delivery Details

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Delivery Details’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_T_DELIVERY_S as select from zte_t_delivery_s
{
key delivery_id as DeliveryId,
customer_id as CustomerId,
material as Material,
price as Price,
delivery_date as DeliveryDate,
delivery_status as DeliveryStatus
}

 Root view For Billing Details

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Billing Details’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_T_BILLING_S as select from zte_t_billing_s
{
key billing_id as BillingId,
customer_id as CustomerId,
delivery_id as DeliveryId,
material as Material,
price as Price
}

STEP 3: Create Projection View 

  • Add UI Annotations
  • Add Action Button In Delivery Projection

Projection View For Delivery Details

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Delivery Details’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_T_DELIVERY_S
provider contract transactional_query as projection on ZI_T_DELIVERY_S
{
@UI.facet: [{ id: ‘deliverdetails’,
position: 1,
label: ‘Order Details’,
type: #IDENTIFICATION_REFERENCE
} ]
@UI.lineItem: [
{ importance: #MEDIUM},
{ position: 10, type : #FOR_ACTION, label : ‘Available’, dataAction : ‘create_delivery’ },
{ position: 1, label : ‘Delivery ID’ }]
@UI.identification: [{ position: 1, label : ‘Delivery ID’ }]
key DeliveryId,
@UI.lineItem: [{ position: 2, label : ‘Customer ID’ }]
@UI.identification: [{ position: 2, label : ‘Customer ID’ }]
CustomerId,
@UI.lineItem: [{ position: 3, label : ‘Material’ }]
@UI.identification: [{ position: 3, label : ‘Material’ }]
Material,
@UI.lineItem: [{ position: 4, label : ‘Price’ }]
@UI.identification: [{ position: 4, label : ‘Price’ }]
Price,
@UI.lineItem: [{ position: 5, label : ‘Delivery Date’ }]
@UI.identification: [{ position: 5, label : ‘Delivery Date’ }]
DeliveryDate,
@UI.lineItem: [{ position: 6, label : ‘Delivery Status’ }]
@UI.identification: [{ position: 6, label : ‘Delivery Status’ }]
DeliveryStatus
}

Projection View for Billing Details

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Billing Details’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_T_BILLING_S
provider contract transactional_query as projection on ZI_T_BILLING_S
{
@UI.facet: [{ id: ‘Billingdetails’,
position: 1,
label: ‘Billing Details’,
type: #IDENTIFICATION_REFERENCE
} ]
@UI.lineItem: [{ position: 1, label : ‘Billing Id’ }]
@UI.identification: [{ position: 1, label : ‘Billing Id’ }]
key BillingId,
@UI.lineItem: [{ position: 2, label : ‘Customer Id’ }]
@UI.identification: [{ position: 2, label : ‘Custoomer Id’ }]
CustomerId,
@UI.lineItem: [{ position: 3, label : ‘Delivery Id’ }]
@UI.identification: [{ position: 3, label : ‘Delivery Id’ }]
DeliveryId,
@UI.lineItem: [{ position: 4, label : ‘Material’ }]
@UI.identification: [{ position: 4, label : ‘Material’ }]
Material,
@UI.lineItem: [{ position: 5, label : ‘Price’ }]
@UI.identification: [{ position: 5, label : ‘Price’ }]
Price
}

STEP 4: Define Behavior Definitions
 Delivery BO behavior

  • Enable CRUD operation
  • Declare a non-factory action

This Action is responsible for creating Billing data and updating delivery status

managed implementation in class zbp_i_t_delivery_s unique;
strict ( 2 );
define behavior for ZI_T_DELIVERY_S //alias <alias_name>
persistent table zte_t_delivery_s
lock master
authorization master ( instance )
//etag master <field_name>
{
create;
update;
delete;
action create_delivery result [1] $self;
mapping for zte_t_delivery_s
{
DeliveryId = delivery_id;
CustomerId = customer_id;
Material = material;
Price = price;
DeliveryDate = delivery_date;
DeliveryStatus = delivery_status;
}
}

Billing BO behavior

  • Enable CRUD operations
  • use Late Numbering for auto-generating Billing Id

managed implementation in class zbp_i_t_billing_s unique;
strict ( 2 );
define behavior for ZI_T_BILLING_S //alias <alias_name>
persistent table zte_t_billing_s
lock master
authorization master ( instance )
late numbering
//etag master <field_name>
{
create;
update;
delete;

mapping for zte_t_billing_s
{
BillingId = billing_id;
DeliveryId = delivery_id;
CustomerId = customer_id;
Material = material;
Price = price;
}
}

STEP 5: Define Projection behavior 

Delivery BO projection behavior

projection;
strict ( 2 );
define behavior for ZC_T_DELIVERY_S //alias <alias_name>
{
use create;
use update;
use delete;
use action create_delivery;
}

Billing BO projection behavior

projection;
strict ( 2 );
define behavior for ZC_T_BILLING_S //alias <alias_name>
{
use create;
use update;
use delete;
}

STEP 6:  Implement Behavior Logic

Delivery Class

CLASS lhc_ZI_T_DELIVERY_S DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR zi_t_delivery_s RESULT result.

METHODS create_delivery FOR MODIFY
IMPORTING keys FOR ACTION zi_t_delivery_s~create_delivery RESULT result.
ENDCLASS.

CLASS lhc_ZI_T_DELIVERY_S IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.

METHOD create_delivery.
READ ENTITIES OF ZI_T_DELIVERY_S
IN LOCAL MODE
ENTITY ZI_T_DELIVERY_S
FIELDS ( DeliveryId CustomerId Material Price )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_delivery).
LOOP AT lt_delivery INTO DATA(ls_delivery).

“Create Billing Entry
MODIFY ENTITIES OF ZI_T_BILLING_S
ENTITY ZI_T_BILLING_S
CREATE
FIELDS ( DeliveryId CustomerId Material Price )
WITH VALUE #(
(
%cid = ‘BILL1’
DeliveryId = ls_delivery-DeliveryId
CustomerId = ls_delivery-CustomerId
Material = ls_delivery-Material
Price = ls_delivery-Price
)
)
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).

IF ls_failed IS NOT INITIAL.
reported = CORRESPONDING #( ls_reported ).
RETURN.
ENDIF.

“Update Delivery Status
MODIFY ENTITIES OF ZI_T_DELIVERY_S
IN LOCAL MODE
ENTITY ZI_T_DELIVERY_S
UPDATE FIELDS ( DeliveryStatus )
WITH VALUE #(
(
DeliveryId = ls_delivery-DeliveryId
DeliveryStatus = ‘DELIVERED’
)
).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Billing Class

CLASS lhc_ZI_T_BILLING_S DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR zi_t_billing_s RESULT result.
ENDCLASS.

CLASS lhc_ZI_T_BILLING_S IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
ENDCLASS.

CLASS lsc_ZI_T_BILLING_S DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS adjust_numbers REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.

CLASS lsc_ZI_T_BILLING_S IMPLEMENTATION.
METHOD adjust_numbers.
SELECT FROM ZTE_T_Billing_S FIELDS MAX( billing_id ) INTO (ls_mat_num).
DATA(lv_num) = ls_mat_num+3(4).
LOOP AT mapped-zi_t_billing_s ASSIGNING FIELD-SYMBOL(<fs_material>).
lv_num += 1.
<fs_material>-BillingId = |BIL{ lv_num ALPHA = IN WIDTH = 4 }|.
ENDLOOP.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.

STEP 7: Service Defination

Expose Both Behavior objects

@EndUserText.label: ‘Delivery and billing details’
define service ZSD_T_DETAILS {
expose ZC_T_DELIVERY_S;
expose ZC_T_BILLING_S;
}

STEP 8 : Service Binding

  • create service binding
  • Activate and publish

Screenshot 2026-04-14 111025.png

STEP 9: RESULT

Create a record and click on the Action Button the delivery Status will be updated and Billing records will be created 

Screenshot 2026-04-14 111910.png

Billing details when Action is trigged and Delivery status updated to Delivery

Screenshot 2026-04-14 112132.png

Conclusion

Cross Business Object operations in RAP are essential for building real-world enterprise applications. While RAP abstracts much of the complexity, designing such interactions requires a clear understanding of:

  • Transactional behavior
  • BO independence vs coordination
  • Framework-driven data consistency By leveraging RAP Actions and EML, we can safely orchestrate multi-BO updates without compromising on clean architecture or data integrity.

This example demonstrates how a simple Delivery trigger can drive Billing creation, showcasing a scalable pattern that can be extended to more complex business processes.

“}]] 

  Read More Technology Blog Posts by Members articles 

#abap

By ali

Leave a Reply