In the previous exercise, you've defined and implemented validations (see Exercise 6).
In this exercise, you will implement the different actions defined for the Travel Bo entity in Exercise 3:
- The instance actions
acceptTravel
andrejectTravel
to accept or reject travel instances with one click. - The internal instance action
reCalcTotalPrice
to recalculate the total price of a travel instance when needed. - The static default factory instance action
createTravel
with parameter that will be used to replace the standardcreate
operation.
- 7.0: How to handle this exercise
- 7.1: Implement the Instance Actions
acceptTravel
andrejectTravel
- 7.2: Implement the Internal Instance Action
reCalcTotalPrice
- 7.3: Implement the Static Factory Action with Parameter
createTravel
- 7.4: Preview and Test the Enhanced Travel App
- Summary
Reminder: Do not forget to replace the suffix placeholder
###
with your choosen or assigned assigned suffix in the exercise steps below.
Click to expand!
In the RAP context, an action is a non-standard operation that change the data of a BO instance.
Actions are specified in behavior definitions and implemented in ABAP behavior pools. By default, actions are related to instances of a BO entity. The addition
static
allows you to define a static action that are not bound to any instance but relates to the complete entity.Two main categories of actions can be implemented in RAP:
- Non-factory actions: Defines a RAP action which offers non-standard behavior. The custom logic must be implemented in the RAP handler method
FOR MODIFY
. An action per default relates to a RAP BO entity instance and changes the state of the instance. An action is related to an instance by default. Non-factory actions can be instance-bound (default) or static.- Factory actions: Factory actions are used to create RAP BO entity instances. Factory actions can be instance-bound (default) or static. Instance-bound factory actions can copy specific values of an instance. Static factory actions can be used to create instances with prefilled default values.
ℹ Further reading: Actions | CDS BDL - non-standard operations | ABAP EML - response_param
ℹ Further reading: RAP BO Contract | RAP BO Provider API (derived types, %cid, implicit response parameters,...)
Enhance the behavior implementation class of the travel entity with the business logic for the action methods
acceptTravel
,rejectTravel
,reCalcTotalPrice
, andcreateTravel
.
💡 There are two (2) ways to complete exercise 6.1:
Option 1️⃣: This is the recommended option. Carry out this step (Exercise 7.0) and then proceed directly with Exercise 7.4.
Option 2️⃣: Skip this step (7.0) and proceed with the steps 7.1-7.4 in sequence.
🔵 Click to expand!
-
Go to the behavior implementation class of the travel entity
ZRAP110_BP_TRAVELTP_### and adjust it.
For that, replace the whole source code on the Local Types tab with the source code provided in the source code document linked below and replace the placeholder
###
with your assigned suffix.▶📄 Source code document:
Behavior Implementation Class ZRAP110_BP_TRAVELTP_###
-
Now, specify the static factory action
createTravel
as default in the behavior definition of the travel entityZRAP110_R_TRAVELTP_###
.For that, add the keyword
default
after the keywordstatic
as shown on the screenshot below. -
Save
and activate
the changes.
Now, the static default factory action
createTravel
will be automatically called by the SAP Fiori elements UI instead of the standardcreate
operation. -
You can now proceed directly with Exercise 7.4.
You will now implement the logic of the instance actions
acceptTravel
andrejectTravel
in the local handler classLhc_travel
of the behavior pool of the travel BO entity. These actions are used to set the overall status of a given travel instance respectively to accepted or rejected in one click. Both actions have been defined in Exercise 3.4:
action acceptTravel result [1] $self;
action rejectTravel result [1] $self;
The definition, implementation and exposuse of instance actions is covered and explained in RAP100. Therefore, simply copy the business logic provided as code snippet below in your travel behavior pool
ZRAP110_BP_TRAVELTP_###
to enhance the functionality of your Travel app.These instance actions will be needed in Exercise 11: Enhance the BO Behavior with Business Events.
🔵 Click to expand!
Implement the action behavior in the local handler method
acceptTravel
of the behavior pool of the travel entity.
🟣 Click to expand!
-
Go to the method
acceptTravel
of the local handler classlhc_travel
in the behavior implementation classZRAP110_BP_TRAVELTP_###
and replace the empty method implementation with the code provide below.Replace all occurences of the placeholder
###
with your assigned suffix.************************************************************************** * Instance-bound action acceptTravel ************************************************************************** METHOD acceptTravel. MODIFY ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY travel UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky OverallStatus = travel_status-accepted ) ). " 'A' Accepted " read changed data for result READ ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(travels). result = VALUE #( FOR travel IN travels ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
Implement the action behavior in the local handler method
rejectTravel
of the behavior pool of the travel entity.
🟣 Click to expand!
-
Go to the method
rejectTravel
of the local handler classlhc_travel
in the behavior implementation classZRAP110_BP_TRAVELTP_###
and replace the empty method implementation with the code provide below.Replace all occurences of the placeholder
###
with your assigned suffix.************************************************************************** * Instance-bound action rejectTravel ************************************************************************** METHOD rejectTravel. MODIFY ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY travel UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky OverallStatus = travel_status-rejected ) ). " 'X' Rejected " read changed data for result READ ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(travels). result = VALUE #( FOR travel IN travels ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
You will now implement the logic of the internal instance action
reCalcTotalPrice
in the local handler classlhc_travel
of the behavior pool of the travel BO entity. This action is used to calculate the total price of a given travel instance. The total price is the sum of the booking fee (BookingFee
) of a travel entity instance and the flight price (FlightPrice
) of each associated booking entity instances. The currency (CurrencyCode
) is considered in this calculation. This action has been defined in Exercise 3.4:
internal action recalcTotalPrice;
The implementation of internal instance actions is similar to the one of classic instance actions such as
acceptTravel
andrejectTravel
. The only difference is that internal actions are private and can only be used within the given BO.The internal instance action
reCalcTotalPrice
will be needed in Exercise 8 to enable the recalculation ofTotalPrice
at specific trigger point.
🔵 Click to expand!
-
Go to the method
reCalcTotalPrice
of the local handler classlhc_travel
in the behavior implementation classZRAP110_BP_TRAVELTP_###
and replace the empty method implementation with the code provide below.⚠ Please note: Only few currency codes conversion factors are currently maintained in the present system D23.
Replace all occurences of the placeholder
###
with your assigned suffix.************************************************************************** * Internal instance-bound action calculateTotalPrice ************************************************************************** METHOD reCalctotalprice. TYPES: BEGIN OF ty_amount_per_currencycode, amount TYPE /dmo/total_price, currency_code TYPE /dmo/currency_code, END OF ty_amount_per_currencycode. DATA: amounts_per_currencycode TYPE STANDARD TABLE OF ty_amount_per_currencycode. " Read all relevant travel instances. READ ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY Travel FIELDS ( BookingFee CurrencyCode ) WITH CORRESPONDING #( keys ) RESULT DATA(travels). DELETE travels WHERE CurrencyCode IS INITIAL. " Read all associated bookings and add them to the total price. READ ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY Travel BY \_Booking FIELDS ( FlightPrice CurrencyCode ) WITH CORRESPONDING #( travels ) LINK DATA(booking_links) RESULT DATA(bookings). LOOP AT travels ASSIGNING FIELD-SYMBOL(<travel>). " Set the start for the calculation by adding the booking fee. amounts_per_currencycode = VALUE #( ( amount = <travel>-bookingfee currency_code = <travel>-currencycode ) ). LOOP AT booking_links INTO DATA(booking_link) USING KEY id WHERE source-%tky = <travel>-%tky. " Short dump occurs if link table does not match read table, which must never happen DATA(booking) = bookings[ KEY id %tky = booking_link-target-%tky ]. COLLECT VALUE ty_amount_per_currencycode( amount = booking-flightprice currency_code = booking-currencycode ) INTO amounts_per_currencycode. ENDLOOP. DELETE amounts_per_currencycode WHERE currency_code IS INITIAL. CLEAR <travel>-TotalPrice. LOOP AT amounts_per_currencycode INTO DATA(amount_per_currencycode). " If needed do a Currency Conversion IF amount_per_currencycode-currency_code = <travel>-CurrencyCode. <travel>-TotalPrice += amount_per_currencycode-amount. ELSE. /dmo/cl_flight_amdp=>convert_currency( EXPORTING iv_amount = amount_per_currencycode-amount iv_currency_code_source = amount_per_currencycode-currency_code iv_currency_code_target = <travel>-CurrencyCode iv_exchange_rate_date = cl_abap_context_info=>get_system_date( ) IMPORTING ev_amount = DATA(total_booking_price_per_curr) ). <travel>-TotalPrice += total_booking_price_per_curr. ENDIF. ENDLOOP. ENDLOOP. " write back the modified total_price of travels MODIFY ENTITIES OF ZRAP110_R_TravelTP_### IN LOCAL MODE ENTITY travel UPDATE FIELDS ( TotalPrice ) WITH CORRESPONDING #( travels ). ENDMETHOD.
You will now implement the logic of the static factory action (with parameter)
createTravel
in the local handler classlhc_travel
of the behavior pool of the travel BO entityZRAP110_BP_TRAVELTP_###
. The action has been defined in Exercise 3.4:
static factory action createTravel parameter ZRAP110_A_Create_Travel_### [1];
Then you will specify the action as
default static factory action
in the behavior definitionof the travel entity .
ℹ Info about Factory Action:
- With factory actions, you can create entity instances by executing an action.
- Static actions are not bound to any instance but relate to the complete entity. So, instance factory actions can be useful if you want to copy specific values of an instance, whereas static factory actions can be used to create instances with prefilled default values. A factory action always has the result cardinality [1].
- The default option specifies a static factory action as the new
create
operation that will be called by the SAP Fiori elements UI instead of the standardcreate
operation.The implementation of an instance-bound factory action is covered and explained in RAP100.
🔵 Click to expand!
-
You can have a look at the CDS abstract entity
ZRAP110_A_Create_Travel_###
. It will be used to define the structure of the input parameter.Have a look at the source code of the abstract entity
Below is the formatted source code:
@EndUserText.label: 'Parameter for Creating Travel+Booking' define abstract entity ZRAP110_A_Create_Travel_### { @Consumption.valueHelpDefinition: [ { entity: { name: '/DMO/I_Customer_StdVH', element: 'CustomerID' } } ] customer_id : /dmo/customer_id; @Consumption.valueHelpDefinition: [ { entity: { name: '/DMO/I_Flight_StdVH', element: 'AirlineID' }, additionalBinding: [ { localElement: 'flight_date', element: 'FlightDate', usage: #RESULT }, { localElement: 'connection_id', element: 'ConnectionID', usage: #RESULT } ] } ] carrier_id : /dmo/carrier_id; @Consumption.valueHelpDefinition: [ { entity : { name: '/DMO/I_Flight_StdVH', element: 'AirlineID' }, additionalBinding: [ { localElement: 'flight_date', element: 'FlightDate', usage: #RESULT }, { localElement: 'carrier_id', element: 'AirlineID', usage: #FILTER_AND_RESULT } ] } ] connection_id : /dmo/connection_id; @Consumption.valueHelpDefinition: [ { entity: { name: '/DMO/I_Flight_StdVH', element: 'AirlineID' }, additionalBinding: [ { localElement: 'carrier_id', element: 'AirlineID', usage: #FILTER_AND_RESULT }, { localElement: 'connection_id', element: 'ConnectionID', usage: #FILTER_AND_RESULT } ] } ] flight_date : /dmo/flight_date; }
-
Now, go to the method
createTravel
of the local handler classlhc_travel
in the behavior implementation classZRAP110_BP_TRAVELTP_###
and replace the empty method implementation with the code provide below.Replace all occurences of the placeholder
###
with your assigned suffix.************************************************************************** * static default factory action createTravel ************************************************************************** METHOD createTravel. IF keys IS NOT INITIAL. SELECT * FROM /dmo/flight FOR ALL ENTRIES IN @keys WHERE carrier_id = @keys-%param-carrier_id AND connection_id = @keys-%param-connection_id AND flight_date = @keys-%param-flight_date INTO TABLE @DATA(flights). "create travel instances with default bookings MODIFY ENTITIES OF ZRAP110_R_TRAVELTP_### IN LOCAL MODE ENTITY Travel CREATE FIELDS ( CustomerID Description ) WITH VALUE #( FOR key IN keys ( %cid = key-%cid %is_draft = key-%param-%is_draft CustomerID = key-%param-customer_id Description = 'Own Create Implementation' ) ) CREATE BY \_Booking FIELDS ( CustomerID CarrierID ConnectionID FlightDate FlightPrice CurrencyCode ) WITH VALUE #( FOR key IN keys INDEX INTO i ( %cid_ref = key-%cid %is_draft = key-%param-%is_draft %target = VALUE #( ( %cid = i %is_draft = key-%param-%is_draft CustomerID = key-%param-customer_id CarrierID = key-%param-carrier_id ConnectionID = key-%param-connection_id FlightDate = key-%param-flight_date FlightPrice = VALUE #( flights[ carrier_id = key-%param-carrier_id connection_id = key-%param-connection_id flight_date = key-%param-flight_date ]-price OPTIONAL ) CurrencyCode = VALUE #( flights[ carrier_id = key-%param-carrier_id connection_id = key-%param-connection_id flight_date = key-%param-flight_date ]-currency_code OPTIONAL ) ) ) ) ) MAPPED mapped. ENDIF. ENDMETHOD.
-
Now, specify the static factory action
createTravel
as default in the behavior definition of the travel entityZRAP110_R_TRAVELTP_###
.Add the keyword
default
after the keywordstatic
as shown on the screenshot below. -
Save
and activate
the changes.
Now, the static default factory action
createTravel
will be automatically called by the SAP Fiori elements UI instead of the standardcreate
operation.
You can test the enhanced SAP Fiori elements app can be tested.
🔵 Click to expand!
-
You can either refresh your application in the browser using F5 if the browser is still open - or go to your service binding
ZRAP110_UI_TRAVEL_O4_###
and start the Fiori elements App preview for theTravel
entity set. -
Play around. For example,...
-
Press the buttons Accept Travel and Reject Travel to change the overall status of travel instances.
-
Press the button Create. The logic of the
createTravel
should be called now -
Create or Edit an existing entry to check the calculation of the total price.
⚠ Please not that the execution of the internal action
reCalcTotalPrice
is not yet triggered. Therefore, the total price of a travel instance will not be calculated for now. You will tackle this in the next exercise by implementing the determinationcalculateTotalPrice
.After clicking Create you will get following pop-up. Here you can select all enties at once. This is pop-up appears due to the key word default.
-
Now that you've implemented and tested...
- instance actions,
- internal instance actions, and
- static default factory instance actions,
you can continue with the next exercise – Exercise 8: Implement the Base BO Behavior - Determinations