Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
1,110

Hi Everyone,

Scenario : Sending an Email for a Selected Record Using the RAP Model

Introduction:

In an SAP S/4HANA system, there is a need to send an email notification when a user selects or processes a specific record in a RAP (RESTful ABAP Programming)–based application. For example, when a sales order, request, or approval record is selected in the Fiori Elements app, an email should automatically be triggered to the responsible user or approver.

1. Creation of Table :

@EndUserText.label : 'Service Header Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zva_hdr_service {
  key client    : abap.clnt not null;
  key serviceno : zva_serviceno not null;
  servicename   : zva_servicename;
  startdate     : abap.dats;
  enddate       : abap.dats;
  @Semantics.amount.currencyCode : 'zva_hdr_service.currency'
  amount        : abap.curr(8,2);
  currency      : abap.cuky;
  createdby     : uname;
  createdon     : datum;

}

2. Creation of Root View Entity

In the SAP RESTful ABAP Programming Model (RAP), the Root View Entity is the main CDS view entity that defines the data model and structure of the root business object.
It serves as the entry point for the RAP business object and forms the foundation for its behavior and service exposure.

A Root View Entity is defined using the CDS keyword define root view entity. It typically represents the main database table or a combination of tables that store the business data.

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Root View'
@Metadata.ignorePropagatedAnnotations: true
define root view entity zva_header_serv_root as select from zva_hdr_service as Service
{
key Service.serviceno as Serviceno,
Service.servicename as Servicename,
Service.startdate as Startdate,
Service.enddate as Enddate,
@Semantics.amount.currencyCode: 'currency'
Service.amount as Amount,
Service.currency as Currency
}

 

3. Creation of  Projection View  for Root  View Entity:

In SAP RAP, a Projection View is a Core Data Services (CDS) view that defines which parts of a Business Object (BO) — specifically its data and associations — are exposed to the outside world (for example, through an OData service or Fiori app).

It acts as a public interface of your business object.
While the Root View Entity defines the complete internal data model, the Projection View determines the external view that users or external systems can access.

 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Projection View'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity ZVA_HEADER_SERV_ROOT_pro as projection on zva_header_serv_root as Service
{
    key Service.Serviceno,
    Service.Servicename,
    Service.Startdate,
    Service.Enddate,
    @Semantics.amount.currencyCode: 'Currency'
    Service.Amount,
    Service.Currency
}

4. Creation of Metadata Extensions for Projection View:

Metadata extensions are used to define UI-specific annotations for CDS views. They allow the separation of concerns by keeping the data model independent of UI-related semantics. These extensions are particularly useful for defining Fiori UI layouts and behaviors without modifying the underlying CDS view.

 

@Metadata.layer: #CORE
annotate entity ZVA_HEADER_SERV_ROOT_pro
    with 
{
   
    :{ lineItem:[{ type: #FOR_ACTION , dataAction: 'SendEmail',label: 'Email' } ] }
    :{ lineItem:[{  position:1  }],
          selectionField: [{ position: 1 ,element: 'Serviceno'  }] }
    Serviceno;
    :{ lineItem: [{ label: 'Service Name' , position:2  }],
          selectionField: [{ position: 2 ,element: 'Servicename'  }] }
    Servicename;
    : { lineItem: [{ label: 'Start Date' , position:3  }],
            selectionField: [{ position: 3,element: 'Startdate'  }]       }
    Startdate;
     : { lineItem: [{ label: 'End Date' , position:4 }],
            selectionField: [{  position: 4 ,element: 'Enddate'}] }
    Enddate;
    .lineItem: [{ label: 'Amount' , position:5  }]
    Amount;
    .lineItem: [{ label: 'Currency' , position:6 }]
    Currency;  
}

5. Creation of Root  Abstract  Entity :

Root Abstract Entity is a CDS construct designed for modeling complex input parameters or non-standard operations in RAP. Unlike root view entities, abstract entities are not tied to database tables.

 

@EndUserText.label: 'Email'
define root abstract entity zva_email_send
{
//    Email : char200; 
    Email : zva_email;  
}

 

6. Creation of Behavior Definition for Root View or Consumption View and implement the classes:

Behavior Definition (BDEF) is a key component that defines the transactional behavior of a RAP Business Object (BO). It specifies how the BO can be accessed and manipulated by consumers, such as creating, updating, or deleting records. The BDEF is always tied to a Core Data Services (CDS) data model, which includes at least one root entity.

A BDEF consists of two main parts: a header and one or more entity behavior definitions. The header defines the overall behavior, while the entity behavior definitions specify the characteristics and operations for each entity. These operations include standard actions like createupdate, and delete, as well as custom actions, determinations, and validations.

 

managed implementation in class zbp_va_header_serv_root unique;
strict ( 2 );
define behavior for zva_header_serv_root alias Service
persistent table ZVA_HDR_SERVICE
lock master
authorization master ( instance )
//etag master <field_name>
{
  action SendEmail parameter zva_email_send;
}

Place the cursor on the class name, press  ( Ctrl + 1 ), choose Implement the  Class, and then activate the class.

CLASS lhc_Service DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.
    METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
      IMPORTING keys REQUEST requested_authorizations FOR Service RESULT result.
    METHODS SendEmail FOR MODIFY
      IMPORTING keys FOR ACTION Service~SendEmail.
ENDCLASS.
CLASS lhc_Service IMPLEMENTATION.
  METHOD get_instance_authorizations.
  ENDMETHOD.
  METHOD SendEmail.
  ENDMETHOD.
ENDCLASS.

Implementation of SendEmail Method:

  " Implementation of the custom action SendEmail
  METHOD SendEmail.
    " Get the first selected record from the action context
    DATA(ls_keys) = VALUE #( keys[ 1 ] OPTIONAL ).
    DATA(p_email) = ls_keys-%param-Email.
    "-------------------------
    " Step 1: Validate email
    "-------------------------
    IF p_email IS INITIAL.
      " No email provided -> return error message
      APPEND VALUE #( %tky = ls_keys-%tky
                      %msg = new_message( id = 'ZVA_MSG'
                                          number = '000'
                                          severity = if_abap_behv_message=>severity-error ) )
             TO reported-Service.
      RETURN.
    ENDIF.

    IF NOT p_email CP '*@*.*'.
      " Invalid email format -> return error message
      APPEND VALUE #( %tky = ls_keys-%tky
                      %msg = new_message( id = 'ZVA_MSG'
                                          number = '001'
                                          severity = if_abap_behv_message=>severity-error ) )
             TO reported-Service.
      RETURN.
    ENDIF.

    "-------------------------
    " Step 2: Read service data
    "-------------------------
    READ ENTITIES OF zva_header_serv_root
      ENTITY Service
      ALL FIELDS
      WITH VALUE #( ( Serviceno = ls_keys-Serviceno ) )
      RESULT DATA(lt_serv).

    DATA(ls_serv) = lt_serv[ 1 ].

    "-------------------------
    " Step 3: Prepare and send email
    "-------------------------
    TRY.
        " Create persistent send request (BCS)
        DATA(lo_send_request) = cl_bcs=>create_persistent( ).

        " Prepare HTML email body
        DATA: lt_body TYPE soli_tab,
              lv_html TYPE string,
              lv_text TYPE string.

        lv_text = 'Hi Good Morning..'.

        " Add HTML table header
        CONCATENATE
          '<html><body>'
          '<p>' lv_text '</p>'
          '<h3>Service Details</h3>'
          '<table border="1" cellpadding="8" cellspacing="0" style="border-collapse:collapse;">'
          '<tr>'
          '<th>Service Number</th>'
          '<th>Service Name</th>'
          '<th>StartDate</th>'
          '<th>EndDate</th>'
          '<th>Amount</th>'
          '</tr>'
          INTO lv_html SEPARATED BY space.

        APPEND lv_html TO lt_body.
        CLEAR lv_html.

        " Add dynamic service data rows
        LOOP AT lt_serv INTO ls_serv.
          DATA(lv_amount) = ls_serv-Amount.
          CONCATENATE
            '<tr>'
            '<td>' ls_serv-Serviceno '</td>'
            '<td>' ls_serv-Servicename '</td>'
            '<td>' ls_serv-Startdate '</td>'
            '<td>' ls_serv-Enddate '</td>'
            '<td>' lv_amount '</td>'
            '</tr>'
            INTO lv_html SEPARATED BY space.
          APPEND lv_html TO lt_body.
          CLEAR lv_html.
        ENDLOOP.

        " Set up document object for the email
        DATA(lo_document) = cl_document_bcs=>create_document(
                              i_type    = 'HTM'
                              i_text    = lt_body
                              i_subject = 'Service Details' ).

        " Add document to send request
        lo_send_request->set_document( lo_document ).

        " Set sender as current SAP user
        lo_send_request->set_sender( cl_sapuser_bcs=>create( sy-uname ) ).

        " Add recipient email
        lo_send_request->add_recipient(
          i_recipient = cl_cam_address_bcs=>create_internet_address( p_email ),
          i_express   = abap_true ).

        " Send the email
        DATA(lv_sent_to_all) = lo_send_request->send( ).

    ENDTRY.

    "-------------------------
    " Step 4: Show success or error messages
    "-------------------------
    IF lv_sent_to_all = abap_true.
      " Email sent successfully
      APPEND VALUE #( %tky = ls_keys-%tky
                      %msg = new_message( id = 'ZVA_MSG'
                                          number = '002'
                                          severity = if_abap_behv_message=>severity-success ) )
             TO reported-Service.
    ELSE.
      " Email sending failed
      APPEND VALUE #( %tky = ls_keys-%tky
                      %msg = new_message( id = 'ZVA_MSG'
                                          number = '003'
                                          severity = if_abap_behv_message=>severity-error ) )
             TO reported-Service.
    ENDIF.
  ENDMETHOD.

 

7. Creation of Behavior Definition for Projection View and Implement the classes :

Behavior Projection maps the transactional capabilities of the base behavior definition to a projection view. This allows for further customization of the behavior for specific use cases. For example:

projection implementation in class zbp_va_header_serv_root_pro unique;
strict ( 2 );
define behavior for ZVA_HEADER_SERV_ROOT_pro //alias <alias_name>
{
 use action SendEmail ;
}

  Place the cursor on the class name, press  ( Ctrl + 1 ), choose Implement the  Class, and then activate the class.

vinodkumarreddyappannagari_0-1762167079334.png

8. Creation of Service Definition for Consumption View :

vinodkumarreddyappannagari_1-1762167271502.png

@EndUserText.label: 'Service Definition'
define service ZVA_HEADER_SERV_ROOT_PRO_SD {
  expose ZVA_HEADER_SERV_ROOT_pro;
}

9. Creation of Service Binding for Service Definition:

vinodkumarreddyappannagari_0-1762167831491.png

Click on public button and activate 

vinodkumarreddyappannagari_1-1762167958764.png

 

Click on preview button  then navigate the fiori .

Screenshot 2025-11-03 163745.png

Screenshot 2025-11-03 164133.png

Click on a Email button then open a popup then provide the email id.

vinodkumarreddyappannagari_0-1762168588704.png

if email id is not provided it's shows the error and incorrect email provided also shows a error message. 

vinodkumarreddyappannagari_1-1762168619343.png

vinodkumarreddyappannagari_2-1762168743938.png

vinodkumarreddyappannagari_3-1762168756550.png

 

Screenshot 2025-11-03 152748.png

Email sent successful then shows the success message.

vinodkumarreddyappannagari_6-1762168821678.png

Go to SOST  t-code we will check the the record.

Screenshot 2025-12-10 184410.png

Select the record and click on display button

Screenshot 2025-11-03 165445.png

Summary: 

In this implementation, a custom action SendEmail is added to a RAP BO to allow users to send an email containing service details directly from the application.

 1. Email Validation

The action first retrieves the email ID passed through the action parameters.
It performs two validations:

  • Checks if the email field is empty

  • Checks if the email format is valid using a simple pattern *@*.*
    If the validation fails, an error message is returned using RAP messaging.

2. Reading Service Data

The code reads the selected service record from the root entity (zva_header_serv_root) using READ ENTITIES.
The retrieved fields are later used to dynamically build the email content.

 3. Building and Sending the Email

The email is sent using SAP Business Communication Services (BCS):

  • A persistent send request (cl_bcs) is created

  • An HTML email body is built, including:

    • Greeting text

    • A formatted HTML table

    • Dynamically added service details

  • The document is attached to the send request as an HTML email (HTM)

  • Sender is set as the logged-in SAP user

  • Recipient is the email address entered by the user

  • The email is finally sent using send( )

4. Success & Error Handling

After sending, the system returns:

  • A success message if the email was sent

  • An error message if the sending process failed

These messages are reported back through RAP’s reported- structure.

ABAP Development ,

SAP Fiori for SAP S/4HANA ,

2 Comments
sap_cohort
Active Contributor

Great coverage.  Lot of development effort though!   Thanks for the contribution.

zfiori
Participant
0 Likes

Hi Community,

" Metadata extensions are used to define UI-specific annotations for CDS views. They allow the separation of concerns by keeping the data model independent of UI-related semantics. These extensions are particularly useful for defining Fiori UI layouts and behaviors without modifying the underlying CDS view. "

 

Thanks for your kindly sharing, it really help us a lot.

 

 

🙂

 

Regards,

ZFiori.