By

Dynamic Feature Control in RAP

In this article, we will add a dynamic feature control on field “Agency ID” in our RAP application.

  1. Go to Behavior Definition

Add feature instance for Booking association.

Code snippet showing a class definition for a travel management system, including an association for creating a booking instance.

We will control the creation of booking on specific condition.

Save and Activate

2. Use quick fix to generate code for dynamic feature

Screenshot of code editing interface showing a method definition for a travel entity and instructions for adding a missing method.
Code snippet showing a method definition in a programming language, including 'METHOD get_instance_features.' and 'ENDMETHOD.' statements.

  METHOD get_instance_features.

  "Fetch Travel data with status
  reaD ENTITIES OF zha_sa_travel in lOCAL MODE
  enTITY Travel
  fIELDS (  TravelId OverallStatus )
  wITH corRESPONDING #(  keys )
  resULT data(lt_travel)
  failed failed.

  "Return the result with booking creation feature possibility
  read table lt_travel intO data(ls_travel) inDEX 1.
  if ( ls_travel-OverallStatus = 'X' )."rejected
  data(lv_allow) = if_abap_behv=>fc-o-disabled.
  else.
  lv_allow = if_abap_behv=>fc-o-enabled.
  endIF.

  result = vaLUE #(  for travel in lt_travel
                    ( %tky = travel-%tky
                      %assoc-_Booking = lv_allow  ) ).


  ENDMETHOD.

Save and Activate

3. Full Code

Behavior Implementation Class

CLASS lhc_Travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Travel RESULT result.
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR Travel RESULT result.
METHODS copyTravel FOR MODIFY
IMPORTING keys FOR ACTION Travel~copyTravel.
METHODS get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Travel RESULT result.
METHODS earlynumbering_create FOR NUMBERING
IMPORTING entities FOR CREATE Travel.
METHODS earlynumbering_cba_Booking FOR NUMBERING
IMPORTING entities FOR CREATE Travel\_Booking.
ENDCLASS.
CLASS lhc_Travel IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD get_global_authorizations.
ENDMETHOD.
METHOD earlynumbering_create.
DATA: entity TYPE STRUCTURE FOR CREATE zha_sa_travel,
travel_id_max TYPE /dmo/travel_id.
"Validate Travel ID
LOOP AT entities INTO entity WHERE TravelId IS NOT INITIAL.
APPEND CORRESPONDING #( entity ) TO mapped-travel.
ENDLOOP.
DATA(lt_entities) = entities.
DELETE lt_entities WHERE TravelId IS NOT INITIAL.
"Get number range from SNRO
TRY.
cl_numberrange_runtime=>number_get(
EXPORTING
nr_range_nr = '01'
object = CONV #( '/DMO/TRAVL' )
quantity = CONV #( lines( lt_entities ) )
IMPORTING
number = DATA(number_range_key)
returncode = DATA(number_range_return_code)
returned_quantity = DATA(number_range_returned_quantity)
).
CATCH cx_number_ranges INTO DATA(lx_number_ranges).
LOOP AT lt_entities INTO entity.
APPEND VALUE #( %cid = entity-%cid %key = entity-%key %msg = lx_number_ranges )
TO reported-travel.
APPEND VALUE #( %cid = entity-%cid %key = entity-%key ) TO failed-travel.
ENDLOOP.
EXIT.
ENDTRY.
CASE number_range_return_code.
WHEN '1'.
"Number range exceeded
LOOP AT lt_entities INTO entity.
APPEND VALUE #( %cid = entity-%cid %key = entity-%key
%msg = NEW /dmo/cm_flight_messages(
textid = /dmo/cm_flight_messages=>number_range_depleted
severity = if_abap_behv_message=>severity-warning ) )
TO reported-travel.
ENDLOOP.
WHEN '2' OR '3'.
APPEND VALUE #( %cid = entity-%cid %key = entity-%key
%msg = NEW /dmo/cm_flight_messages(
textid = /dmo/cm_flight_messages=>not_sufficient_numbers
severity = if_abap_behv_message=>severity-warning ) )
TO reported-travel.
APPEND VALUE #( %cid = entity-%cid %key = entity-%key
%fail-cause = if_abap_behv=>cause-conflict )
TO failed-travel.
ENDCASE.
"Check all numbers
ASSERT number_range_returned_quantity = lines( lt_entities ).
"Assign the number range to the mapped data
travel_id_max = number_range_key - number_range_returned_quantity.
LOOP AT lt_entities INTO entity.
travel_id_max += 1.
entity-TravelId = travel_id_max.
reported-%other = VALUE #( ( new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = 'Travel id has been created.') ) ).
APPEND VALUE #( %cid = entity-%cid
%key = entity-%key ) TO mapped-travel.
ENDLOOP.
ENDMETHOD.
METHOD earlynumbering_cba_Booking.
DATA lv_max_booking_id TYPE /dmo/booking_id.
"read Travel data
READ ENTITIES OF zha_sa_travel IN LOCAL MODE
ENTITY travel BY \_Booking
FROM CORRESPONDING #( entities )
LINK DATA(bookings).
"Loop on unique Travel Id
LOOP AT entities ASSIGNING FIELD-SYMBOL(<lfs_travel_grp>) GROUP BY <lfs_travel_grp>-TravelId.
"Get highest booking number
LOOP AT bookings INTO DATA(ls_booking) USING KEY entity
WHERE source-TravelId = <lfs_travel_grp>-TravelId.
IF lv_max_booking_id < ls_booking-target-BookingId.
lv_max_booking_id = ls_booking-target-BookingId.
ENDIF.
ENDLOOP.
"Get assigned booking numbers
LOOP AT entities INTO DATA(ls_entity) USING KEY entity
WHERE travelId = <lfs_travel_grp>-TravelId.
LOOP AT ls_entity-%target INTO DATA(ls_target).
IF lv_max_booking_id < ls_target-BookingId.
lv_max_booking_id = ls_target-BookingId.
ENDIF.
ENDLOOP.
ENDLOOP.
"Loop on entities
LOOP AT entities ASSIGNING FIELD-SYMBOL(<lfs_travel>)
USING KEY entity WHERE TravelId = <lfs_travel_grp>-TravelId.
"Assign booking id to booking entity for each Travel Id
LOOP AT <lfs_travel>-%target ASSIGNING FIELD-SYMBOL(<lfs_booking>).
APPEND CORRESPONDING #( <lfs_booking> ) TO mapped-booking ASSIGNING FIELD-SYMBOL(<lfs_mapped_booking>).
IF <lfs_mapped_booking>-BookingId IS INITIAL.
lv_max_booking_id += 10.
<lfs_mapped_booking>-BookingId = lv_max_booking_id.
ENDIF.
ENDLOOP.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
METHOD copyTravel.
DATA: travels TYPE TABLE FOR CREATE zha_sa_travel\\Travel,
bookings_cba TYPE TABLE FOR CREATE zha_sa_travel\\Travel\_Booking,
bookingsuppl_cba TYPE TABLE FOR CREATE zha_sa_travel\\Booking\_BookingSupplement.
"Remove the travel instances with initial ID
READ TABLE keys WITH KEY %cid = '' INTO DATA(key_with_intitial_cid).
ASSERT key_with_intitial_cid IS INITIAL.
"Read travel, Booking and booking supplement using EML
READ ENTITIES OF zha_sa_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(travel_read_result)
FAILED failed.
READ ENTITIES OF zha_sa_travel IN LOCAL MODE
ENTITY Travel BY \_Booking
ALL FIELDS WITH CORRESPONDING #( travel_read_result )
RESULT DATA(booking_read_result)
FAILED failed.
READ ENTITIES OF zha_sa_travel IN LOCAL MODE
ENTITY booking BY \_BookingSupplement
ALL FIELDS WITH CORRESPONDING #( booking_read_result )
RESULT DATA(booksuppl_read_result)
FAILED failed.
"Fill Travel internal table for Travel data creation
LOOP AT travel_read_result ASSIGNING FIELD-SYMBOL(<lfs_travel>).
"Travel data prepration
APPEND VALUE #( %cid = keys[ %tky = <lfs_travel>-%tky ]-%cid
%data = CORRESPONDING #( <lfs_travel> EXCEPT travelId )
) TO travels ASSIGNING FIELD-SYMBOL(<lfs_new_travel>).
<lfs_new_travel>-BeginDate = cl_abap_context_info=>get_system_date( ).
<lfs_new_travel>-EndDate = cl_abap_context_info=>get_system_date( ) + 30.
"Fill booking internal table for booking data creation
APPEND VALUE #( %cid_ref = keys[ KEY entity %tky = <lfs_travel>-%tky ]-%cid )
TO bookings_cba ASSIGNING FIELD-SYMBOL(<lfs_bookings_cba>).
LOOP AT booking_read_result ASSIGNING FIELD-SYMBOL(<lfs_booking>) WHERE TravelId = <lfs_travel>-TravelId.
APPEND VALUE #( %cid = keys[ KEY entity %tky = <lfs_travel>-%tky ]-%cid && <lfs_booking>-BookingId
%data = CORRESPONDING #( booking_read_result[ KEY entity %tky = <lfs_booking>-%tky ] EXCEPT TravelId ) )
TO <lfs_bookings_cba>-%target ASSIGNING FIELD-SYMBOL(<lfs_new_boking>).
<lfs_new_boking>-BookingStatus = 'N'.
"Fill booking supplement internal table for booking supplement data creation
APPEND VALUE #( %cid_ref = keys[ KEY entity %tky = <lfs_travel>-%tky ]-%cid && <lfs_booking>-BookingId )
TO bookingsuppl_cba ASSIGNING FIELD-SYMBOL(<lfs_booksuppl_cba>).
LOOP AT booksuppl_read_result ASSIGNING FIELD-SYMBOL(<lfs_booksuppl>)
USING KEY entity WHERE TravelId = <lfs_travel>-TravelId AND BookingId = <lfs_booking>-BookingId.
APPEND VALUE #( %cid = keys[ KEY entity %tky = <lfs_travel>-%tky ]-%cid && <lfs_booking>-BookingId && <lfs_booksuppl>-BookingSupplementId
%data = CORRESPONDING #( <lfs_booksuppl> EXCEPT TravelId BookingId ) )
TO <lfs_booksuppl_cba>-%target.
ENDLOOP.
ENDLOOP.
ENDLOOP.
"Create a New BO instance using existing data
MODIFY ENTITIES OF zha_sa_travel IN LOCAL MODE
ENTITY Travel
CREATE FIELDS ( AgencyId CustomerId BeginDate EndDate BookingFee TotalPrice CurrencyCode OverallStatus )
WITH travels
CREATE BY \_Booking FIELDS ( Bookingid BookingDate CustomerId CarrierId ConnectionId FlightDate FlightPrice CurrencyCode BookingStatus )
WITH bookings_cba
ENTITY Booking
CREATE BY \_BookingSupplement FIELDS ( bookingsupplementid supplementid price currencycode )
WITH bookingsuppl_cba
MAPPED DATA(mapped_create).
mapped-travel = mapped_create-travel.
ENDMETHOD.
METHOD get_instance_features.
"Fetch Travel data with status
reaD ENTITIES OF zha_sa_travel in lOCAL MODE
enTITY Travel
fIELDS ( TravelId OverallStatus )
wITH corRESPONDING #( keys )
resULT data(lt_travel)
failed failed.
"Return the result with booking creation feature possibility
read table lt_travel intO data(ls_travel) inDEX 1.
if ( ls_travel-OverallStatus = 'X' )."rejected
data(lv_allow) = if_abap_behv=>fc-o-disabled.
else.
lv_allow = if_abap_behv=>fc-o-enabled.
endIF.
result = vaLUE #( for travel in lt_travel
( %tky = travel-%tky
%assoc-_Booking = lv_allow ) ).
ENDMETHOD.
ENDCLASS.

Behavior Definition

 managed;
 strict ( 2 );
 define behavior for zha_sa_travel alias Travel
 implementation in class zbp_ha_sa_travel unique
 persistent table /dmo/travel_m
 lock master
 authorization master ( instance )
 //To autogenerate Travel ID
 early numbering
 etag master LastChangedAt
 {

   create ( authorization : global);
   update;
   delete;
   field ( readonly ) TravelId;
   field ( mandatory ) AgencyId, CustomerId, BeginDate, EndDate, OverallStatus,BookingFee, CurrencyCode;

   //Data action to create new instance
   factory action copyTravel[1];

   association _Booking { create ( features:instance ); }
   mapping for /dmo/travel_m
     {
       TravelId      = travel_id;
       AgencyId      = agency_id;
       CustomerId    = customer_id;
       BeginDate     = begin_date;
       EndDate       = end_date;
       TotalPrice    = total_price;
       CurrencyCode  = currency_code;
       BookingFee    = booking_fee;
       LastChangedAt = last_changed_at;
       LastChangedBy = last_changed_by;
       CreatedAt     = created_at;
       CreatedBy     = created_by;
       OverallStatus = overall_status;
       Description   = description;
     }
 }
 define behavior for zha_sa_booking alias Booking
 implementation in class zbp_ha_sa_booking unique
 persistent table /dmo/booking_m
 lock dependent by _Travel
 authorization dependent by _Travel
 etag master LastChangedAt
 early numbering
 {

   update;
   delete;
   field ( readonly ) TravelId, BookingId;
   field ( mandatory ) CarrierId, ConnectionId, FlightDate, BookingStatus;
   association _Travel;
   association _BookingSupplement { create; }
   mapping for /dmo/booking_m
     {
       TravelId      = travel_id;
       BookingId     = booking_id;
       BookingDate   = booking_date;
       CustomerId    = customer_id;
       CarrierID     = carrier_id;
       ConnectionId  = connection_id;
       FlightDate    = flight_date;
       CurrencyCode  = currency_code;
       BookingStatus = booking_status;
       LastChangedAt = last_changed_at;
     }
 }
 define behavior for zha_sa_booksuppl alias BookingSuppl
 implementation in class zbp_ha_sa_booksuppl unique
 persistent table /dmo/booksuppl_m
 lock dependent by _Travel
 authorization dependent by _Travel
 etag master LastChangedAt
 early numbering
 {
   update;
   delete;
   field ( readonly ) TravelId, BookingId;
   field ( mandatory) Price, SupplementId;
   association _Travel;
   association _Booking;
   mapping for /dmo/booksuppl_m
     {
       TravelId            = travel_id;
       BookingId           = booking_id;
       BookingSupplementId = booking_supplement_id;
       SupplementId        = supplement_id;
       price               = price;
       CurrencyCode        = currency_code;
       LastChangedAt       = last_changed_at;
     }
 }

4. Output

If the Travel request is open user will be able to create booking and if it is rejected then creation of booking is not allowed.

Click on Open Status Travel request

Screenshot of a travel request management interface in the SAP Fiori Elements App, showing multiple travel requests with their details, including travel IDs, agency IDs, customer IDs, and overall statuses. The 'Vacation' request for 'Kirk' is highlighted with an 'Open' status.

As you can see Create option is available for Over Status = ‘Open’

Screenshot of a travel booking interface showing vacation details, including travel ID, customer ID, agency details, dates, and pricing information. An option to create a new booking is highlighted.

Go back and click on rejected Travel request

Screenshot of SAP Fiori Elements App displaying a list of travel requests with various statuses, including accepted, open, and rejected requests.

As you can see Create Booking option is not available for rejected Travel requests

Screenshot of a travel booking system section displaying a rejected vacation status. Total price is $6,085.00 USD. Includes booking details such as travel ID, customer ID, agency ID, dates, and pricing information.

Thanks for reading!

Previous/Next

Leave a Reply

Discover more from HANAxABAP

Subscribe now to keep reading and get access to the full archive.

Continue reading