Application Development and Automation Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Krishna_karale
Explorer
1,075

Hello Everyone, 

 In this blog post we are going to Learn about Global Feature Control in RAP.   

Global feature control in the RAP (RESTful Application Programming) model is used to enable or disable specific features for all users at once, regardless of individual data records or instances. It defines whether a particular operation (like create, update, or delete) is globally allowed or restricted. To do this, we extend the operation in the behavior definition as we did earlier for the instance feature.   

Delete (features: global); 

To implement a global feature, the "get_global_features" method must be implemented. As previously described, there is no transfer of the keys from the outside. The derivation of the various features must be based on other criteria. 

Procedure:

Here we are defining a Custom table (ZKK_DT_TRAVEL). 

The table zkk_dt_travel is a transparent table in SAP that stores travel-related information. It includes details such as travel ID, agency ID, customer ID, travel dates, booking fees, total price, currency, status and a description. It also tracks the creation and modification details like created by, created at, last changed by, and last changed at. 

@EndUserText.label : 'Travel table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zkk_dt_travel {

  key client      : abap.clnt not null;
  key travel_id   : /dmo/travel_id not null;
  agency_id       : /dmo/agency_id;
  customer_id     : /dmo/customer_id;
  begin_date      : /dmo/begin_date;
  end_date        : /dmo/end_date;
  @Semantics.amount.currencyCode : '/dmo/travel_m.currency_code'
  booking_fee     : abap.curr(16,2);
  @Semantics.amount.currencyCode : '/dmo/travel_m.currency_code'
  total_price     : /dmo/total_price;
  currency_code   : /dmo/currency_code;
  description     : /dmo/description;
  status          : abap_boolean;
  created_by      : abp_creation_user;
  created_at      : abp_creation_tstmpl;
  last_changed_by : abp_locinst_lastchange_user;
  last_changed_at : abp_locinst_lastchange_tstmpl;

}

The Above table holds the records which are given below 

Krishna_karale_0-1742974513709.png

For this database table(ZKK_DT_TRAVEL) we are defining the Basic view/Interface view. 

The ZKK_I_TRAVEL is a CDS view based on the zkk_dt_travel  table. It provides a structured way to access travel data, including fields like travel ID, agency ID, customer ID, travel dates, booking fees, total price, currency, and timestamps. It uses annotations to enhance usability, such as semantic tags for amounts, currencies, and metadata for created/changed users and timestamps. 

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface view for Travelling'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define root view entity ZKK_I_TRAVEL
  as select from zkk_dt_travel
{
  key travel_id       as TravelId,
      agency_id       as AgencyId,
      customer_id     as CustomerId,
      begin_date      as BeginDate,
      end_date        as EndDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      booking_fee     as bookingfee,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      total_price     as TotalPrice,
      currency_code   as CurrencyCode,
      description     as Description,
      status          as status,
      @Semantics.user.createdBy: true
      created_by      as CreatedBy,
      @Semantics.systemDateTime.createdAt: true
      created_at      as CreatedAt,
      @Semantics.user.localInstanceLastChangedBy: true
      last_changed_by as LastChangedBy,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at as LastChangedAt
}

 Now I am defining the Projection view on top of interface view. 

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'projection view for Travel'
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define root view entity ZKK_C_TRAVEL  
  as projection on ZKK_I_TRAVEL as Travel
{
  key TravelId,
      AgencyId,
      CustomerId,
      BeginDate,
      EndDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      bookingfee,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      TotalPrice,
      CurrencyCode,
      Description,
      status,
      CreatedBy,
      CreatedAt,
      LastChangedBy,
      LastChangedAt
}

Now I am defining the Metadata Extension for projection View.

@Metadata.layer: #PARTNER
annotate entity ZKK_C_TRAVEL with
{
  @ui.facet: [{
     purpose: #STANDARD,
     position: 10,
     type : #IDENTIFICATION_REFERENCE,
     label: 'Travel Details'
   }]

  @ui.identification: [{ position: 10, label: 'Travel Id' }]
  @ui.lineItem: [{ label: 'Travel Id' }]
  TravelId;

  @ui.identification: [{ position: 20, label: 'Agency Id' }]
  @ui.lineItem: [{ label: 'Agency Id' }]
  AgencyId;

  @ui.identification: [{ position: 30, label: 'Customer Id' }]
  @ui.lineItem: [{ label: 'Customer Id' }]
  CustomerId;

  @ui.identification: [{ position: 40, label: 'Begin Date' }]
  @ui.lineItem: [{ label: 'Begin Date' }]
  BeginDate;

  @ui.identification: [{ position: 50, label: 'End Date' }]
  @ui.lineItem: [{ label: 'End Date' }]
  EndDate;

  @ui.identification: [{ position: 60, label: 'Booking Fee' }]
  @ui.lineItem: [{ label: 'Booking Fee' }]
  bookingfee;

  @ui.identification: [{ position: 70, label: 'Total Price' }]
  @ui.lineItem: [{ label: 'Total Price' }]
  TotalPrice;

  @ui.identification: [{ position: 80, label: 'Status Confirm' },
  { type: #FOR_ACTION, dataAction: 'status', label: 'Status Confirm' } ]
  @ui.lineItem: [{ label: 'Status' },
  { type: #FOR_ACTION, dataAction: 'status', label: 'Confirm Status' }]
  status;


  @ui.identification: [{ position: 100, label: 'Currency' }]
  @ui.lineItem: [{ label: 'Currency' }]
  CurrencyCode;

  @ui.identification: [{ position: 90, label: 'Description' }]
  @ui.lineItem: [{ label: 'Description' }]
  Description;


  @ui.identification: [{ position: 110, label: 'Created By' }]
  @ui.lineItem: [{ label: 'Created By' }]
  CreatedBy;

  @ui.identification: [{ position: 120, label: 'Created At' }]
  @ui.lineItem: [{ label: 'Created At' }]
  CreatedAt;

  @ui.identification: [{ position: 130, label: 'Last Changed By' }]
  @ui.lineItem: [{ label: 'Last Changed By' }]
  LastChangedBy;

  @ui.identification: [{ position: 140, label: 'Last Changed At' }]
  @ui.lineItem: [{ label: 'Last Chnaged at' }]
  LastChangedAt;
}

Lets Define the Behaviour Definition.

managed implementation in class zbp_kk_i_travel unique;
strict ( 2 );

define behavior for ZKK_I_TRAVEL alias Travel //alias <alias_name>
persistent table zkk_dt_travel
lock master
authorization master ( instance )
//etag master <field_name>
{
  create;
  update;
  delete ( features : global );
  field ( readonly : update ) TravelId;
  field ( readonly ) LastChangedAt, LastChangedBy, CreatedAt, CreatedBy;
  field ( mandatory : create ) AgencyId, CustomerId, BeginDate, EndDate, bookingfee, CurrencyCode;
  action ( features : instance ) status result [1] $self;

  mapping for ZKK_DT_TRAVEL {
  TravelId = travel_id;
  AgencyId = agency_id;
  CustomerId = customer_id;
  BeginDate = begin_date;
  EndDate = end_date;
  bookingfee = booking_fee;
  TotalPrice = total_price;
  CurrencyCode = currency_code;
  Description = description;
  status = status;
  CreatedBy = created_by;
  CreatedAt = created_at;
  LastChangedBy = last_changed_by;
  LastChangedAt = last_changed_at;
  }
}

Here in Behavior definition, we have to specify 

delete (features: global); 

as we are performing delete operation 

After that we will get a warning as given below 

Krishna_karale_1-1742974809833.png

When we double click on that warning GET_GLOBAL_FEATURE method will get automatically. 

Krishna_karale_2-1742974895719.png

You can observe there is no KEYS parameter, that means we cannot read the details of selected record from here, we will get only the global data. 

Now we have to implement our custom logic inside the above given method. 

 METHOD get_global_features.

  if requested_features-%delete = if_abap_behv=>mk-on.
  Data(lv_result) = COND #( when cl_abap_context_info=>get_user_alias(  ) = 'xyz@gmail.com'
                           then if_abap_behv=>mk-on
                           else if_abap_behv=>mk-off
                            ).

  result-%delete = lv_result.

  ENDIF.

  ENDMETHOD.

 Here we have to take the username or mail id which is registed on your SAP Universal ID, so for example i have taken 'xyz@gmail.com'.

Above logic is to make delete button enable or disable 

When the user is xyz@gmail.com then the delete button will be enabled  

(Requested features contains the actions which are specified with (features: global))  

Preview the data 

The user logged-in is xyz@gmail.com 

Krishna_karale_3-1742975170990.png

The delete button is enabled 

Rewriting the code 

When the user is xyz@gmail.com then i want the delete button to be disabled 

 METHOD get_global_features.

  if requested_features-%delete = if_abap_behv=>mk-on.
  Data(lv_result) = COND #( when cl_abap_context_info=>get_user_alias(  ) = 'xyz@gmail.com'
                           then if_abap_behv=>mk-off
                           else if_abap_behv=>mk-on
                            ).

  result-%delete = lv_result.

  ENDIF.

  ENDMETHOD.

When we RUN the application. 

We dont get Delete option as enables, here it is disable for that particular user.Krishna_karale_4-1742975387698.png

Conclusion: 

Global feature control in RAP provides a centralized way to enable or disable specific operations across the entire application, regardless of individual records or user roles. It ensures consistent enforcement of business rules by globally restricting actions like create, update, or delete. This approach simplifies feature management, enhances data security, and ensures uniform behavior, making it an effective mechanism for controlling access and operations at the application level. 

 

2 Comments
Faizan_khan1
Explorer

Great Blog , Thank you for sharing this information

Jelena_Perfiljeva
Active Contributor
0 Kudos

Thanks for sharing! It's probably best not to use the user's identifying information like this though.

For reference, this is Help article on the subject with the links to more detailed documentation and examples.

Labels in this area