In the previous exercise, you've enhanced the data model of the base Travel BO entity, the projected Travel BO entity, and the projected booking BO entity (see Exercise 2).
In this exercise, you will enhance the transactional behavior of your Travel BO. You will define the Late Numbering for drawing the primary of the travel and the booking entities, the static and dynamic feature control for fields, standard and nonstandard operations, validations, instance and factory actions, determinations, and functions.
- 3.1 - How to handle this exercise 💡
- 3.2 - Define the Late Numbering and the Static Field Control
- 3.3 - Define the Validations
- 3.4 - Define the Actions
- 3.5 - Define the Determinations
- 3.6 - Define the Functions
- 3.7 - Define the Dynamic Feature Control
- 3.8 - Adjust the Behavior Implementation Classes
- 3.9 - Enhance the BO Behavior Projection
- Summary
Reminder: Do not forget to replace the suffix placeholder
###
with your assigned suffix in the exercise steps below.
ℹ Click to expand!
ℹ Click to expand!
Numbering is about setting values for primary key fields of entity instances during runtime. Different types of numbering are supported in RAP which can be divided into two main categories:
- Early numbering: In an early numbering scenario, the primary key value is set instantly after the modify request for the
CREATE
is executed. The key values can be passed externally by the consumer or can be set internally by the framework or an implementation of theFOR NUMBERING
method.- Late numbering: In a late numbering scenario, the key values are always assigned internally without consumer interaction after the point of no return in the interaction phase has passed, and the
SAVE
sequence is triggered. The latter will be implemented in the present exerciseFurther reading: Numbering
ℹ Click to expand!
Validations are used to ensure the data consistency.
As the name suggests, front-end validations are performed on the UI. They are used to improve the user experience by providing faster feedback and avoiding unnecessary roundtrips. In the RAP context, front-end validations are defined using CDS annotation or UI logic.
On the other hand, back-end validations are performed on the back-end. They are defined in the BO behavior definitions and implemented in the respective behavior pools.
Frontend validations can be easily bypassed - e.g. by using EML APIs in the RAP context. Therefore, backend validations are a MUST to ensure the data consistency.In RAP, front-end validations are defined with the attribute
usedForValidation
in value helps defined with the element annotation@Consumption.valueHelpDefinition
.Further reading: Validations
ℹ 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 actions that are not bound to any instance but relates to the complete entity. The additioninternal
define a private action that can only be called within the given BO.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,...)Further reading: Actions
ℹ Click to expand!
A determination is an optional part of the business object behavior that modifies instances of business objects based on trigger conditions. A determination is implicitly invoked by the RAP framework if the trigger condition of the determination is fulfilled. Trigger conditions can be modify operations and modified fields. A determination can be triggered
on modify
oron save
.Further reading: Determinations
ℹ Click to expand!
As an application developer you may want to determine based on certain attributes of your business object entity, which fields should be read-only or mandatory or which functionality like update or actions are allowed. As this property is related to an instance of this business object it is called Dynamic Feature Control.
ℹ Further reading: Adding Static and Dynamic Feature Control
💡 There are two (2) ways to complete this exercise:
Option 1️⃣: This is the recommended option. Carry out this step (3.1) to replace the whole content of your behavior definiton with the provided source code and then proceed directly with step 3.8 of the present exercise. Of course you can quickly go over the steps 3.2-3.7 to understand the enhanced behavior.
Option 2️⃣: Skip this step (3.1) and carry out the steps 3.2-3.9 in sequence.
🔵 Click to expand!
-
Open the base behavior definition
ZRAP110_R_TRAVELTP_###
of the Travel BO. -
Enhance the behavior definition of the Travel BO with late numbering, validations, actions, determinations and a function. The static field control and the feature control will also be enhanced.
For that, replace the whole source code of your behavior definition object with the source code from the document provided below.
Replace all occurences of the placeholder
###
with your assigned suffix using Ctrl+F.▶📄 Source code document:
CDS Behavior Definition ZRAP110_R_TRAVELTP_###
-
You're now getting errors indicating that the fields
DRAFTUUID
andPARENTDRAFTUUID
which are required in the draft tables by late numering are currently missing.this is due to the fact that any draft entity needs to have a key in order to be managed properly by the RAP frameworks in the interaction phase, until a primary key is drawn during late phase of the save sequence. To achieve this, a uuid-based key is required for the draft entities. Therefore, the travel and booking draft tables needs to be re-created.
-
Recreate the draft table for travel entities:
ZRAP110_DTRAV###
.Set your cursor on the table name, press Ctrl+1, and select the entry
Recreate draft table zrap110_dtrav### for entity zrap110_r_traveltp_###.
in the Quick Assist view.The draft table is now enhanced.
-
Save
and activate
the changes.
Close the travel database table definition and go back to the behavior definition.
-
Now, recreate the draft table for booking entities:
ZRAP110_DBOOK###
.Set your cursor on the table name, press Ctrl+1, and select the entry
Recreate draft table zrap110_dtrav### for entity zrap110_r_traveltp_###.
in the Quick Assist view.The draft table is now enhanced.
-
Save
and activate
the changes.
Close the booking database table definition and go back to the behavior definition.
-
As last step, save
(Ctrl+S) and activate
(Ctrl+F3) the changes in the behavior definition.
-
You can now go ahead directly with Exercise 3.8 to adjust the behavior implementation classes, aka behavior pools, of both BO entities_travel_ and _ booking_.
Define the late numbering and the static field control for the travel and booking entities in the BO behavior definition
![]()
ZRAP110_R_TRAVELTP_###
of the Travel BO.
🔵 Click to expand!
🟣 Click to expand!
-
Open the behavior definition
ZRAP110_R_TravelTP_###
of your Travel BO. -
Specify the late numbering statement provided below just after the statement
authorization master( global )
, just before the opening curly bracket{
of the root BO entity travelZRAP110_R_TRAVELTP_###
as shown on the screenshot.late numbering
By doing this, ADT is now requiring an implementation class to be provided at the top level, directly after the keyword
managed
at the top of the editor.You can hover the error for more details.
-
You will implement the late numbering in the behavior implementation class of the travel root entity. Therefore, move the statement
implementation in class zrap110_BP_TravelTP_### unique
to the top as shown on the screenshot. -
Recreate the draft table for travel entities:
ZRAP110_DTRAV###
.Any draft entity needs to have a key in order to be managed properly by the RAP frameworks in the interaction phase, until a primary key is drawn during the save sequence. To achieve this, a uuid-based key is required for the draft entities. Therefore, the existing travel draft table needs to be recreated.
Set your cursor on the table name, press Ctrl+1, and select the entry
Recreate draft table zrap110_dtrav### for entity zrap110_r_traveltp_###.
in the Quick Assist view.The draft table is now enhanced.
-
Save
(Ctrl+S) and activate
(Ctrl+F3) the changes.
Close the database table definition and go ahead with the next step in the behavior definition.
-
Specify the static field control for the Travel BO entity:
TravelID
should be set to read-only as it will be set by the late numbering logic at runtime.TotalPrice
should be set to read-only as will be calculated based on the booking fee (BookingFee
) and the flight price of the associated booking entitiesFlightPrice
.BeginDate
andEndDate
should be specified as mandatory.
Insert the code snippet provided below to the behavior definition as shown on the screenshot.
Replace the readonly
TravelID
with following:field ( readonly ) TravelID; field ( readonly ) TotalPrice; field ( mandatory ) BeginDate, EndDate;
🟣 Click to expand!
-
Now go to the behavior definition
ZRAP110_R_TRAVELTP_###
of the booking child entity located at the bottom of the behavior definition object.Add the late numbering statement just after the statement
authorization master( global )
, before the opening curly bracket{
.late numbering
Now, mutiple error are displayed in ADT. This is due to the fact that a key is required for the draft entity in order to be managed properly by the RAP frameworks in the interaction phase, until a primary key is created during the save sequence.
-
Recreate the draft table for booking entities:
ZRAP110_DBOOK###
.Simply set the mouse cursor on the table name, press Ctrl+1, and select the entry
Recreate draft table zrap110_dbook### for entity zrap110_r_bookingtp_###.
in the Quick Assist view.The draft table is now enhanced.
-
Save
(Ctrl+S) and activate
(Ctrl+F3) the changes.
Close the database table definition and go ahead with the next step in the behavior definition.
-
Specify the static field control for the Booking BO entity:
BookingID
should be set to read-only as this a key field and will be set by the late numbering logic at runtime.CustomerID
,CarrierID
,Flightdate
, andBookingStatus
should be specified as mandatory.
Replace the statement
field ( readonly : update ) BookingID;
with following:field ( readonly ) BookingID; field ( mandatory ) CustomerID, CarrierID, Flightdate, BookingStatus;
Define following validations: to ensure the consitency of the entered data: In the present exercise, you're going to define and implement three back-end validations -
validateCustomer
,validateAgency
, andvalidateDates
- to respectively check if the customer ID and the agency ID that are entered by the consumer are valid, and if the begin date is in the future and the end date is after the begin date. These validations are only performed in the back-end (not on the UI). The validations are triggered independently of the consumer, i.e. Fiori UIs or EML APIs.
⚠ Note: Validations are used to ensure the data consistency. They have been already handled in the RAP100 exercise document. Therefore, we will not go into details about them again. We will simply quickly define and implement some validations that will be use to display other capabilities.
🔵 Click to expand!
🟣 Click to expand!
-
Define three (3) validations to check the values of
CustomerID
,AgencyID
,BeginDate
andEndDate
of the travel root entity. The validations will always be triggeredon save
, i.e. when has to be persisted.Insert the code snippet provided below in the behavior definition of the travel root entity
ZRAP110_R_TRAVELTP_###
as shown on the screeshot below.// validation(s) validation validateCustomer on save { create; field CustomerID; } validation validateAgency on save { create; field AgencyID; } validation validateDates on save { create; field BeginDate, EndDate; }
-
Add the validations to the
draft determine action Prepare
to allow the draft data to be validated before its transition to active data.draft determine action Prepare { validation validateCustomer; validation validateAgency; validation validateDates; }
🟣 Click to expand!
-
Define a validation to check the values of
BookingStatus
. The validation will always be triggeredon save
.Insert the code snippet provided below in the behavior definition
ZRAP110_R_TRAVELTP_###
of the booking child entity.//validation(s) validation validateBookingStatus on save { create; field BookingStatus; }
-
Add the new validation to the
draft determine action Prepare
of the Travel root entity.validation Booking~validateBookingStatus;
Now you will define five (5) different actions for the Travel entity.
- Instance actions
acceptTravel
andrejectTravel
- used to respectively set the overall status of a travel entity to accepted or rejected.- Internal instance action
recalcTotalPrice
- used to recalculate the total price of a travel entity each time either flight price, booking fee, or currency has changed.- Static factory action
createTravel
with input parameter - used to create new travel entities with a booking entity directly - with default values. In a later exercise (Exercise 7 precisely), this action will be marked as default to be used as replacement for the standardcreate
operation. The CDS abstract entity **ZRAP110_A_Create_Travel_###**
will be used to define the structure of the input parameter.- Determine action
checkDates
- used to call the validationvalidateDates
on request.Further reading: Action Definition
🔵 Click to expand!
🟣 Click to expand!
-
Define different actions in the behavior definition of the travel root entity
ZRAP110_R_TRAVELTP_###
.Insert the code snippet provided below and replace the placeholder
###
with your assigned suffix.//action(s) action acceptTravel result [1] $self; action rejectTravel result [1] $self; internal action recalcTotalPrice; static factory action createTravel parameter ZRAP110_A_Create_Travel_### [1]; determine action checkDates { validation validateDates; }
-
Save
(Ctrl+S) the changes and go ahead with the next step.
Brief explanation:
ℹ Click to expand!
- Actions are instance-bound by default.
- The instance actions
acceptTravel
andrejectTravel
return a single travel entity (result [1] $self
). - The action
recalcTotalPrice
has the optioninternal
and can, therefore, only be accessed from the business logic inside the BO implementation such as from a determination or from another action. It has noresult
parameter. - With the option
static
, the factory actioncreateTravel
is not bound to any instance but relates to the complete entity. It has an input parameter and creates an entity instance. - The CDS abstract entity
ZRAP110_A_Create_Travel_###
is used to define the structure of the input parameter. - The action
checkDates
with the optiondetermine
can be called on request via EML or via an action the UI to execute the validationvalidateDates
.
For the travel BO entity, define the on modify determinations
setInitialTravelValues
to set default values of a travel entity instance during its creation andcalculateTotalPrice
to trigger the calculation of the total price of a travel entity instance during its creation and each timeBookingFee
orCurrencyCode
has changed.For the booking BO entity, define the on modify determinations
setInitialBookingValues
to set the default value of a booking entity instance during its creation andcalculateTotalPrice
to trigger the calculation of the total price of the parent travel entity instance during its creation and each timeFlightPrice
orCurrencyCode
has changed.
🔵 Click to expand!
🟣 Click to expand!
-
Define the following
on modify
determinations:setInitialTravelValues
- to set the default value ofBeginDate
,EndDate
,CurrencyCode
, andOverallStatus
during the creation of a travel entity instance.calculateTotalPrice
- to trigger the calculation of the total price of a travel entity on modify at creation time and each timeBookingFee
orCurrencyCode
has changed.
For that, insert the code snippet provided below in the behavior definition of the travel root entity
ZRAP110_R_TRAVELTP_###
as shown on the screenshot.//determination(s) determination setInitialTravelValues on modify { create; } determination calculateTotalPrice on modify { create; field BookingFee, CurrencyCode; }
🟣 Click to expand!
-
Define the following
on modify
determinations:setInitialBookingValues
- to set the default value ofTravelID
,CustomerID
, andBookingDate
during the creation of a travel entity instance on modify.calculateTotalPrice
- to trigger the calculation of the total price of a travel entity on modify at creation time and each timeBookingFee
orCurrencyCode
has changed.
For that, insert the code snippet provided below in the behavior definition of the booking child entity
ZRAP110_R_TravelTP_###
as shown on the screenshot.//determination(s) determination setInitialBookingValues on modify { create; } //copy & paste determination calculateTotalPrice on modify { create; field FlightPrice, CurrencyCode; } //**
For the booking BO entity, define the instance function
getDaysToFlight
to calculate the value of the virtual elementsBookingStatusIndicator
,InitialDaysToFlight
,RemainingDaysToFlight
, andDaysToFlightIndicator
defined in the booking BO projection viewZRAP110_C_TravelTP_###
for a given booking entity instance.
🔵 Click to expand!
🟣 Click to expand!
-
The CDS abstract entity
ZRAP110_A_DAYSTOFLIGHT_###
provided in your exercise packageZRAP110_###
will be used to define the type of the return structure of theresult
parameter.Source code
@EndUserText.label: 'Abstract entity for Days To Flight' define abstract entity ZRAP110_A_DaysToFlight_### { initial_days_to_flight : abap.int4; remaining_days_to_flight : abap.int4; booking_status_indicator : abap.int4; days_to_flight_indicator : abap.int4; }
-
Define the instance function
getDaysToFlight
in the booking child entityZRAP110_R_TravelTP_###
as shown on the screenshot. Replace the placeholder###
with your assigned suffix.//function(s) function getDaysToFlight result [1] ZRAP110_A_DaysToFlight_###;
You will now define the dynamic feature control for some of the standard and nonstandard operations of the Travel entity.
🔵 Click to expand!
🟣 Click to expand!
-
Define the dynamic instance feature control for ...
- the standard operations
update
anddelete
- the standard operation
create
by association for_Booking_
- the instance actions
acceptTravel
andrejectTravel
, and the - the draft action
Edit
To achieve this add the statement below in the behavior definition of the Travel root entity
ZRAP110_R_TRAVELTP_###
as shown on the screenshot.( features : instance )
- the standard operations
You will now adjust the behavior implementation classes, aka behavior pools, of the travel and booking entity to reflect the enhancements specified in both behavior definitions.
🔵 Click to expand!
🟣 Click to expand!
You will now adjust the behavior implementation class (aka behavior pool) of the Travel entity
ZRAP110_BP_TRAVELTP_###
.
-
First, adjust the behavior pool for the late numbering.
The Late numbering is always implemented in the method
adjust_number
of the local saver class of the root BO entity. Therefore, the local saver class and the method must be defined in the behavior pool of the travel entity.For that, go to the behavior definition of the travel entity
ZRAP110_R_TRAVELTP_###
, set the cursor onlate numbering
and press Ctrl+1 to start the ADT Quick Fix.Select
Add required method adjust_number in new local saver class
in the _Quick Assist view to update the behavior pool accordingly.The local saver class
lsc_zrap110_r_traveltp_###
has been added to the behavior pool of the travel BO entityZRAP110_BP_TRAVELTP_###
. -
Now, go ahead and adjust the local handler class for the other enhancements defined in the behavior definition of the travel entity.
For that, set the cursor on one of the new actions, determinations, or validations, e.g.
acceptTravel
, and press Ctrl+1.Select
Add all 10 missing methods of entity zrap110_bp_traveltp_### in local handler class lhc_travel
in the _Quick Assist view to generate the missing methods.The local handler class
lhc_travel
will be updated accordingly. -
Also define the constant
travel_status
in the private section of the local handler class definitionlhc_travel
. It comprises the allowed values of the elementTravelStatus
.⚠ Make sure to define the constant in the local handler class
lhc_travel
- not in the local saver class.It comprises the allowed values of the fields
BookingStatus
Use the code snippet provided below
CONSTANTS: "travel status BEGIN OF travel_status, open TYPE c LENGTH 1 VALUE 'O', "Open accepted TYPE c LENGTH 1 VALUE 'A', "Accepted rejected TYPE c LENGTH 1 VALUE 'X', "Rejected END OF travel_status.
🟣 Click to expand!
You will now adjust the behavior implementation class (aka behavior pool) of the booking entity
ZRAP110_BP_BookingTP_###
-
Now go to the behavior definition
ZRAP110_R_TravelTP_###
, set the cursor on one of the new determinations, validations or the function, e.g.validateBookingStatus
, and press Ctrl+1.Select
Add all 4 missing methods of entity zrap110_bp_bookingtp_### in local handler class lhc_booking
in the _Quick Assist view to generate the missing methods.The local handler class
lhc_booking
will be updated accordingly. -
Also define the constant
booking_status
in the private section of the local handler class definitionlhc_travel
. It comprises the allowed values of the elementBookingStatus
.Use the code snippet provided below
CONSTANTS: "booking status BEGIN OF booking_status, new TYPE c LENGTH 1 VALUE 'N', "New booked TYPE c LENGTH 1 VALUE 'B', "Booked canceled TYPE c LENGTH 1 VALUE 'X', "Canceled END OF booking_status.
You will now expose the new actions defined in the base BO behavior in the BO behavior projection.
INFO: Validations and determinations are automatically orchestrated and called by the RAP frameworks at the specified trigger time. They do not need to be explicetly exposed in the BO projection in order to be used.
🔵 Click to expand!
-
Open the behavior projection
ZRAP110_C_TRAVELTP_###
and add the new actionsacceptTravel
,rejectTravel
,createTravel
, andcheckDates
using the keywordexpose
.Use the code snippet provided below for te purpose as shown on the screenshot.
use action acceptTravel; use action rejectTravel; use action createTravel; use action checkDates;
-
Save
(Ctrl+S) and activate
(Ctrl+F3) the changes. Close the behavior projection.
⚠ Attention ⚠
Due to the specification of late numbering, you will not be able to create new travel or booking instances due to the fact that no key is set at this stage. But no problem, you will tackle it in the next exercise.
Now that you've...
- enhanced the transactional behavior definition of both BO entities, Travel and Booking with
- Late Numbering
- static field control,
- validations,
- actions,
- determinations,
- functions,
- dynamic feature control,
- recreated database tables and adjusted the implementation class definition of the implementation classes with ADT Quick Fixes, and
- exposed the new base BO behavior to the projection layer,
you can continue with the next exercise – Exercise 4: Implement the Base BO Behavior - Late Numbering