In the previous exercise, you've defined and implemented two validations (see Exercise 5).
In the present exercise, you will learn how to add different instance-bound actions (aka instance actions) to your application.
First you will create a non-factory, instance action deductDiscount
, without and with input parameter, to determine the discounted booking fee of a travel instance and the factory instance action copyTravel
to copy a Travel instance.
As optional exercises, you can additionally implement the two non-factory, instance actions acceptTravel
and rejectTravel
to set the overrall status of a Travel instance respectively to accepted (A
) or rejected (X
).
Please note: The purpose of the different exercises is to show you how to implement the different action types - and less on having the perfect business scenario.
- 6.1: Add the Instance-bound Action
deductDiscount
- 6.2: Add the Instance-bound Factory Action
copyTravel
- [OPTIONAL] 6.3: Add the Instance-bound Actions
acceptTravel
andrejectTravel
- Summary
Reminder: Do not forget to replace the suffix placeholder
###
with your choosen or assigned group ID in the exercise steps below.
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.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,...)
You will now define, implement, and expose the action
deductDiscount
, a non-factory instance-bound action returning itself. The action offers the possibility to deduct a certain percentage from the booking fee (BookingFee
) of a Travel instance.The discount percentage can either be fix (30% in the present exercise) in the action implementation or be freely specified by the end-user or the calling APIs by offering an action with input parameters.
You will get familiar with both action implementations, i.e. action without and action with input parameters in the present exercise.
First, define the non-factory, instance action
deductDiscount
in the behavior definition of the Travel entity. This action has no input parameter.
🔵 Click to expand!
-
Go to your behavior definition
ZRAP100_R_TRAVELTP_###
and define the instance action without input paramater.For that, insert the following code snippet after the defined validations as shown on the screenshot below.
action deductDiscount result [1] $self;
The result should look like this:
Short explanation:
- The name of the instance action is specified after the keyword
action
- The keyword
result
defines the output parameter of the action.- Its cardinality is specified between the square brackets (
[cardinality]
). It is a mandatory addition. $self
specifies that the type of the result parameter is the same type as the entity for which the action or function is defined - i.e. the Travel entity type in the present exercise. The return type of the result parameter can be an entity or a structure.
- Its cardinality is specified between the square brackets (
- Note: The output parameter
result
can be used to store the result of an action or function in an internal table. However, it does not affect the result of an action or function that is committed to the database.
ℹ Further reading: Action Definition
- The name of the instance action is specified after the keyword
-
Now, declare the required method in behavior implementation class with the ADT Quick Fix.
Set the cursor on the action name,
deductDiscount
, and press Ctrl+1 to open the Quick Assist view.Select the entry
Add method for action deductDiscount of entity zrap100_r_traveltp_### ...
in the view to add the required method to the local handler class. -
Set the cursor on the method name,
deductDiscount
, press F3 to navigate to the declaration part of the local handler class of the behavior poolZRAP100_BP_TRAVELTP_###
. -
In the declaration part set the cursor on the method name,
deductDiscount
, press F2, and examine the full method interface.Short explanation:
- The addition
FOR MODIFY
after the method name, together with the additionFOR ACTION
after the importing parameter, indicates that this method provides the implementation of an action. - Method signature for the non-factory instance action
deductDiscount
:IMPORTING
parameterkeys
- a table containing the keys of the instances on which the action must be executed- Implicit
CHANGING
parameters (aka implicit response parameters):result
- used to store the result of the performed action.mapped
- table providing the consumer with ID mapping information.failed
- table with information for identifying the data set where an error occurred.reported
- table with data for instance-specific messages.
Please note:
An action is implemented in aFOR MODIFY
method with the additionFOR ACTION
. The signature of an action method always depends on the type of action: factory or non-factory, and instance or static.
The rules for implementing an action operation in a RAP business object are explained in the respective Implementation Contract.ℹ Further reading: Action Implementation | Implementation Contract: Action
Go ahead with the implementation of the action method.
- The addition
Now implement the action behavior in the appropriate method in the behavior pool of the Travel entity.
🔵 Click to expand!
-
Implement the action method
deductDiscount
.The main steps of the implemented business logic:
- Implement the custom logic to determine the new values: The discounted booking fee must be calculated for each instance.
- The discount percentage is fix at the current stage: 30%.
- Modify the relevant fields of the instances with the EML statement
MODIFY
: Here only the fieldBookingFee
must be updated. - Read the data from the buffer with the EML statement
READ
to fill the action result parameterresult
. - The implicit response parameters are filled where necessary:
failed
- with information for identifying the data set where an error occurred.mapped
- table providing the consumer with ID mapping information.reported
- with data for instance-specific messages in case of failure.
Replace the current method implementation with the code snippet provided below and replace all occurrences of the placeholder
###
with your group ID.You can use the ABAP Pretty Printer (Ctrl+F1) to format your source code.
************************************************************************** * Instance-bound non-factory action: * Deduct the specified discount from the booking fee (BookingFee) ************************************************************************** METHOD deductDiscount. DATA travels_for_update TYPE TABLE FOR UPDATE ZRAP100_R_TravelTP_###. DATA(keys_with_valid_discount) = keys. " read relevant travel instance data (only booking fee) READ ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel FIELDS ( BookingFee ) WITH CORRESPONDING #( keys_with_valid_discount ) RESULT DATA(travels). LOOP AT travels ASSIGNING FIELD-SYMBOL(<travel>). DATA(reduced_fee) = <travel>-BookingFee * ( 1 - 3 / 10 ) . APPEND VALUE #( %tky = <travel>-%tky BookingFee = reduced_fee ) TO travels_for_update. ENDLOOP. " update data with reduced fee MODIFY ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( BookingFee ) WITH travels_for_update. " read changed data for action result READ ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( travels ) RESULT DATA(travels_with_discount). " set action result result = VALUE #( FOR travel IN travels_with_discount ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
The result should look like this:
Short explanation:
- The provided implementation is mass-enabled. This is recommended.
- The EML statement
MODIFY ENTITIES ... UPDATE FIELDS
is used to update specific fields of the instances. - The internal tables are filled inline using the constructor operator
VALUE
which made the need for explicit declaration obsolete. - The EML statement
READ ENTITIES ... ALL FIELDS WITH CORRESPONDING
is used to read all fields of the updated instances from the buffer to fill the input paramterresult
.
In contratry to determinations and validations which are automatically called by the RAP runtime at the specified trigger time, actions must be explicitly exposed on the BO projection layer and called by a consumer, e.g. on the UI or directly via EML statements.
Now, you will expose the action in the BO behavior projection and enrich the UI semantics in the CDS metadata extension to add an appropriate button to the Travel App.
🔵 Click to expand!
-
Expose the action in the BO behavior projection.
Go to your behavior projection
ZRAP100_C_TRAVELTP_###
and insert the following code snippet as shown on the screenshot below.The keyword
use action
indicates that a behavior of the base BO is used on the projection layer.use action deductDiscount;
The result should look like this:
-
Enhance UI semantics to make the action
deductDiscount
only visible on the object page with the label Deduct Discount.For that, open your metadata extension
ZRAP100_C_TRAVELTP_###
and replace the existing all@UI
annotation block placed before the elementOverallStatus
with the code snippet provided below as shown on the screenshot below. The semantic of the annotation@UI.identification
will be enhanced for the purpose.Please note: Some lines in the provided code snippet are commented out using
//
at the beginning. DO NOT remove them. You will uncomment these lines in the following exercise steps.@UI: { lineItem: [ { position: 100, importance: #HIGH } //,{ type: #FOR_ACTION, dataAction: 'copyTravel', label: 'Copy Travel' } //,{ type: #FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' } //,{ type: #FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' } ], identification: [ { position: 100 } ,{ type: #FOR_ACTION, dataAction: 'deductDiscount', label: 'Deduct Discount' } //,{ type: #FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' } //,{ type: #FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' } ], textArrangement: #TEXT_ONLY }
The result should look like this:
-
Preview and test the enhanced Fiori elements App.
For example, select a Travel entry, navigate to the object page, and click on the new action button Deduct Discount. Check the action result: the booking fee must have been reduced by the percentage specified in the action method.
If you wish, you can also define the button on the list report page in the CDS metadata extension, activate the changes, and re-test the app.
You will enhance the action
deductDiscount
with an input parameter (discount_percent
) to allow end-users or calling APIs to freely specify the percentage to be deducted from the booking fee (BookingFee
) of a travel instance at runtime.Action input parameters are modeled with abstract CDS entities (abstract entities). In the present example, we will use the abstract entity
/dmo/a_travel_discount
which defines a structure containing only one field,discount_percent
, for the purpose. It is located in the package/DMO/FLIGHT_DRAFT
of the Flight Reference Scenario.
ℹ Info: An abstract CDS entity defines the type properties of a CDS entity. Consequently, it provides metadata on element level or parameter level using CDS annotations and does not have a corresponding implementation nor an underlying persistency.
🔵 Click to expand!
-
Let's have a look at the abstract entity defined in the data definition
/DMO/A_Travel_Discount
. You can use the shortcut Ctrl+Shift+A to open the data definition.Short explanation:
- An abstract entity is defined by the statement
define abstract entity
followed by the CDS entity name. - The current abtract entity defines a structure with only one field or element; The element name (
discount_percent
) and the element type (abap.int1
) are specified. - It is not here the case, but if required, it is possible to...
- specify a label using the element annotation
@EndUserText.label
. - specify a value help using the element annotation
@Consumption.valueHelpDefinition
. - hide an element using the element annotation
@UI.hidden
.
- specify a label using the element annotation
- An abstract entity is defined by the statement
-
Go to the behavior definition
ZRAP100_R_TRAVELTP_###
and add the additionparameter /dmo/a_travel_discount
to the action definition.The source code should now look as follows:
action deductDiscount parameter /dmo/a_travel_discount result [1] $self;
The abstract entity
/dmo/a_travel_discount
is used after the keywordparameter
to specify the parameter structure. The present action will only have one parameter (discount_percent
) as defined in the abstract entity.
You will now adjust the implementation of the business logic for the instance non-factory action
deductDiscount
with the input parameterdeduct_discount
in the behavior poolZRAP100_BP_TRAVELTP_###
.Only entered values greater than
0
and lower than100
will be allowed.
ℹ Info:
Depending on the type of action, the importing parameterkeys
has different components. The parameter structure%param
for parameter input is imported by action with parameters. The parameter structure is used to access the passed values of the input parameters:deduct_discount
in the present scenario - i.e.%param-deduct_discount
.
🔵 Click to expand!
-
Go to your behavior pool
ZRAP100_BP_TRAVELTP_###
and adjust the action methoddeductDiscount
.To adjust the current logic, you will have to retrieve the passed discount values from the parameter structure
%param
and check their validity.The required adjustments of the current business logic:
- For all passed Travel instances: Read and check the validity of the specified discount values from the parameter structure
%param
, and remove invalid ones: 0 <%param-deduct_discount
<= 100 - Implement the custom logic to determine the new values: The discounted booking must be calculated for each instance according to the respective
%param-deduct_discount
value - instead of the fix discount (30%).
Replace the current method implementation with the code snippet provided below. Do not forget to replace all occurrences of the placeholder
###
with your group ID.You can use the ABAP Pretty Printer (Ctrl+F1) to format your source code.
************************************************************************** * Instance-bound non-factory action with parameter `deductDiscount`: * Deduct the specified discount from the booking fee (BookingFee) ************************************************************************** METHOD deductDiscount. DATA travels_for_update TYPE TABLE FOR UPDATE ZRAP100_R_TravelTP_###. DATA(keys_with_valid_discount) = keys. " check and handle invalid discount values LOOP AT keys_with_valid_discount ASSIGNING FIELD-SYMBOL(<key_with_valid_discount>) WHERE %param-discount_percent IS INITIAL OR %param-discount_percent > 100 OR %param-discount_percent <= 0. " report invalid discount value appropriately APPEND VALUE #( %tky = <key_with_valid_discount>-%tky ) TO failed-travel. APPEND VALUE #( %tky = <key_with_valid_discount>-%tky %msg = NEW /dmo/cm_flight_messages( textid = /dmo/cm_flight_messages=>discount_invalid severity = if_abap_behv_message=>severity-error ) %element-TotalPrice = if_abap_behv=>mk-on %op-%action-deductDiscount = if_abap_behv=>mk-on ) TO reported-travel. " remove invalid discount value DELETE keys_with_valid_discount. ENDLOOP. " check and go ahead with valid discount values CHECK keys_with_valid_discount IS NOT INITIAL. " read relevant travel instance data (only booking fee) READ ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel FIELDS ( BookingFee ) WITH CORRESPONDING #( keys_with_valid_discount ) RESULT DATA(travels). LOOP AT travels ASSIGNING FIELD-SYMBOL(<travel>). DATA percentage TYPE decfloat16. DATA(discount_percent) = keys_with_valid_discount[ key draft %tky = <travel>-%tky ]-%param-discount_percent. percentage = discount_percent / 100 . DATA(reduced_fee) = <travel>-BookingFee * ( 1 - percentage ) . APPEND VALUE #( %tky = <travel>-%tky BookingFee = reduced_fee ) TO travels_for_update. ENDLOOP. " update data with reduced fee MODIFY ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( BookingFee ) WITH travels_for_update. " read changed data for action result READ ENTITIES OF ZRAP100_R_TravelTP_### IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( travels ) RESULT DATA(travels_with_discount). " set action result result = VALUE #( FOR travel IN travels_with_discount ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
The result should look like this:
- For all passed Travel instances: Read and check the validity of the specified discount values from the parameter structure
You can now test the new behavior of the action button Deduct Discount` on the enhanced Travel app.
🔵 Click to expand!
-
Preview and test the enhanced Fiori elements Travel App.
Go to the object page of a given entry, click on the new action button Deduct Discount.
A dialog will now be prompted for you to enter a valid discount value, i.e. > 0 and <= 100, and confirm.
Check the result.
You can also repeat the test with an invalid value.
Now, you will define, implement, and expose the action
copyTravel
, an instance-bound factory action used to copy one or moretravel
instances and creates new instances based on the copied data. A new travel ID is assigned to a new travel instance by the unmanaged internal early numbering.
Define the instance factory action
copyTravel
in the behavior definition.
🔵 Click to expand!
-
Go to the behavior definition
ZRAP100_R_TRAVELTP_###
and insert the following code snippet after the action defined in the previous step.factory action copyTravel [1];
The result should look like this:
Short explanation:
For factory actions, the same rules apply as for instance non-factory actions with the following differences:- Instance factory actions are specified with the keyword
factory action
before its name. - Output parameters are not allowed. Factory actions always produce one new BO entity instance with possible child entity instances. It is therefore not necessary to specify the
result
parameter. - The cardinality must always be
[1]
for factory actions. - The result of a factory action is returned in the implicit response parameter
mapped
by a mapping between the BDEF derived type%cid
and the key of the newly created entity instance.
- Instance factory actions are specified with the keyword
ℹ Further information can be found here: CDS BDL - action, factory
Implement the instance factory action
coyTravel
in the base BO behavior pool.
🔵 Click to expand!
-
First declare the required method in the behavior pool.
Go to the behavior definition
ZRAP100_R_TRAVELTP_###
, set the cursor on the action name,copyTravel
, and press Ctrl+1 to open the Quick Assist view.Select the entry
Add method for action copyTravel of entity zrap100_r_traveltp_### ...
in the view to add the required method to the local handler class.The result should look like this:
-
Go to the declaration part of the local handler class of the behavior pool
ZRAP100_BP_TRAVELTP_###
, set the cursor on the method name,copyTravel
, press F2, and examine the full method interface. -
Implement the factory action
copyTravel
in the behavior poolZRAP100_BP_TRAVELTP_###
.ℹ Info:
The implementation method of a factory action imports the parameter structure%param
which has the component%is_draft
. This component can be used by calling EML APIs to indicates the state of the new instance to be created:%is_draft
=00
: New instance must be created as active instance - i.e., must be persisted.%is_draft
=01
: New instance must be created as draft instance - i.e., will first be only stored in the draft table.
The logic consists of the following steps:
- Remove all travel instances with initial ID and read the data from the transfered travel keys to be copied.
- Fill in a travel container (itab) with all the new travel instances to be created. The copied data are adjusted as neeeded.
- The component
%param-%is_draft
indicating the state of the new entity have to be evaluated - and the state of the new instances set accordingly. - In the present exercise, we will adjust the begin date (
BeginDate
) and the end date (EndDate
) due to the implemented validationvalidateDates
and set the overall status of newtravel
instances toOpen
(O
).
- The component
- Create new Travel instances with the EML statement
MODIFY ENTITIES...CREATE
which returns the mapped data. - Set the result set in the
mapped
structure - especially in the internal tablemapped-travel
for the present example.
For that, replace the current method implementation with the code snippet provided below and replace all occurrences of the placeholder
###
with your group ID.************************************************************************** * Instance-bound factory action `copyTravel`: * Copy an existing travel instance ************************************************************************** METHOD copyTravel. DATA: travels TYPE TABLE FOR CREATE zrap100_r_traveltp_###\\travel. " remove travel instances with initial %cid (i.e., not set by caller API) READ TABLE keys WITH KEY %cid = '' INTO DATA(key_with_inital_cid). ASSERT key_with_inital_cid IS INITIAL. " read the data from the travel instances to be copied READ ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(travel_read_result) FAILED failed. LOOP AT travel_read_result ASSIGNING FIELD-SYMBOL(<travel>). " fill in travel container for creating new travel instance APPEND VALUE #( %cid = keys[ KEY entity %key = <travel>-%key ]-%cid %is_draft = keys[ KEY entity %key = <travel>-%key ]-%param-%is_draft %data = CORRESPONDING #( <travel> EXCEPT TravelID ) ) TO travels ASSIGNING FIELD-SYMBOL(<new_travel>). " adjust the copied travel instance data "" BeginDate must be on or after system date <new_travel>-BeginDate = cl_abap_context_info=>get_system_date( ). "" EndDate must be after BeginDate <new_travel>-EndDate = cl_abap_context_info=>get_system_date( ) + 30. "" OverallStatus of new instances must be set to open ('O') <new_travel>-OverallStatus = travel_status-open. ENDLOOP. " create new BO instance MODIFY ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY travel CREATE FIELDS ( AgencyID CustomerID BeginDate EndDate BookingFee TotalPrice CurrencyCode OverallStatus Description ) WITH travels MAPPED DATA(mapped_create). " set the new BO instances mapped-travel = mapped_create-travel . ENDMETHOD.
Your source code should like this:
Expose the instance factory action in the BO behavior projection and in the CDS metadata extension and test the enhance Fiori elements app.
🔵 Click to expand!
-
Expose the new action
copyTravel
in the BO behavior projection.For that, open your behavior projection
ZRAP100_C_TRAVELTP_###
and insert the following code snippet after the actions added previously.use action copyTravel;
The result should like this:
-
Enhance UI semantics of the UI service to make the action
copyTravel
only visible on the list report page with the label Copy Travel.For that, open your CDS metadata extension
ZRAP100_C_TRAVELTP_###
and un-comment following code line in the@UI.lineItem
annotation block placed before the elementOverallStatus
.,{ type: #FOR_ACTION, dataAction: 'copyTravel', label: 'Copy Travel' }
The result should look like this:
-
Preview and test the enhanced Fiori elements app.
Select a travel instance and choose Copy
An object page with the new travel instance opens.
In this step, you will define, implement, and expose two instance-bound non-factory actions for the Travel
entity, acceptTravel
and rejectTravel
. These actions will be used to set the overall status of one or more given Travel instances to Accepted
(A
) and Rejected
(X
) respectively.
⚠ Optional exercise: The non-factory instance ations
acceptTravel
andrejectTravel
defined and implemented in this exercise are similar to the one implemented in the exercise 6.1 (deductDiscount
). They have been added to this document just to offer more functionalities to play with on the Travel app.If you are running out of time, we recommand you go ahead with the next exercise or copy the source code from the provided solution objects provided in the Appendix section.
First, define the instance non-factory actions
acceptTravel
andrejectTravel
in the behavior definition of the Travel entity.
🔵 Click to expand!
-
Go to your behavior definition
ZRAP100_R_TRAVELTP_###
and define both actions.For that, insert the following code snippet after the defined validations as shown on the screenshot below.
action acceptTravel result [1] $self; action rejectTravel result [1] $self;
-
Now, declare the required method in behavior implementation class with the ADT Quick Fix.
Set the cursor on one of the action names,
acceptTravel
orrejectTravel
, and press Ctrl+1 to open the Quick Assist view.Select the entry
Add all 2 missing methods of entity zrap100_r_traveltp_### ...
to add both methods to the local handler classlcl_handler
of the behavior poolZRAP100_BP_TRAVELTP_###
.
You are through with the definition of both actions. Go ahead with the implementations of the two inserted method in the behavior pool.
Now implement the required action methods in the behavior pool
ZRAP100_BP_TRAVELTP_###
of the Travel entity.
🔵 Click to expand!
-
You can check the interfaces of the methods
acceptTravel
andrejectTravel
in the declaration part of the local handler class in the behavior poolZRAP100_BP_TRAVELTP_###
. They are similar to the one of the action methoddeductDiscount
.For that, set the cursor on one of the method name, press F2 to open the ABAP Element Info view, and examine the full method interface.
Go ahead with the implementation.
-
Implement the action
acceptTravel
in the implementation part of the local handler class.
The action is used to set the value of the fieldOverallStatus
to Accepted (A
).The logic consists of the following steps:
- Implement the custom logic to determine the new values; Accepted (
A
) in the present scenario. - Modify the relevant fields of the travel instances; here only the field
OverallStatus
must be updated. - Read the whole data of the updated instances from the buffer to fill the action result parameter.
For that, replace the current method implementation with the code snippet provided below and replace all occurrences of the placeholder
###
with your group ID. You can make use of the F1 Help for more information about the EML statements and other ABAP constructs.************************************************************************************* * Instance-bound non-factory action: Set the overall travel status to 'A' (accepted) ************************************************************************************* METHOD acceptTravel. " modify travel instance MODIFY ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky OverallStatus = travel_status-accepted ) ) " 'A' FAILED failed REPORTED reported. " read changed data for action result READ ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(travels). " set the action result parameter result = VALUE #( FOR travel IN travels ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
Your source code should look like this:
Short explanation:
- The provided implementation is mass-enabled. This is recommended.
- The EML statement
MODIFY ENTITIES ... UPDATE FIELDS
is used to update specific fields of the instances. - The internal tables are filled inline using the constructor operator
VALUE
which made the need for explicit declaration obsolete. - The EML statement
READ ENTITIES ... ALL FIELDS WITH CORRESPONDING
is used to read all fields of the updated instances from the buffer to fill the input paramterresult
.
- Implement the custom logic to determine the new values; Accepted (
-
Implement the action
rejectTravel
which is used to set the value of the fieldOverallStatus
toRejected
(X
). The business logic is similar to the one of theacceptTravel
method.For that, replace the current method implementation with the code snippet provided below and replace all occurrences of the placeholder
###
with your group ID.************************************************************************************* * Instance-bound non-factory action: Set the overall travel status to 'X' (rejected) ************************************************************************************* METHOD rejectTravel. " modify travel instance(s) MODIFY ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( OverallStatus ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky OverallStatus = travel_status-rejected ) ) " 'X' FAILED failed REPORTED reported. " read changed data for action result READ ENTITIES OF zrap100_r_traveltp_### IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(travels). " set the action result parameter result = VALUE #( FOR travel IN travels ( %tky = travel-%tky %param = travel ) ). ENDMETHOD.
Your source code should look like this:
Now, you will expose the actions in the BO behavior projection and enrich the UI semantics in the CDS metadata extension to add appropriate button to the Travel App.
🔵 Click to expand!
-
Expose the actions in the BO behavior projection.
Go to your behavior projection
ZRAP100_C_TRAVELTP_###
and insert the following code snippet as shown on the screenshot below.use action acceptTravel; use action rejectTravel;
Your source code should look like this:
-
Save and activate the changes.
The actions are yet ready to be consumed on the UI, but they also need to be explicitly placed on the UI.
-
Enhance UI semantics of the UI service to make the actions visible on the list report page and the object page; with the labels
Accept Travel
andReject Travel
specified.For that, go to your CDS metadata extension
ZRAP100_C_TRAVELTP_###
and uncomment the relevant code lines in the@UI
annotations block placed before the elementOverallStatus
as shown on the screenshot below. -
You can now preview and test your enhanced Fiori elements app. The actions should now appear on the UI.
For example, select a
Travel
record with the overall status Open and press on the action button Accept Travel or Reject Travel. The overall status should now be Accepted or Rejected.
Now that you've...
- defined different types of instance actions in the behavior definition - i.e simple action, action with input parameter, and factory action,
- implement them in the behavior implementation,
- expose them on the BO projection layer, i.e. behavior projection and metadata extension, and
- preview and test the enhanced Fiori elements app,
you can continue with the next exercise – [Optional] Exercise 7: Enhance the BO Behavior – Dynamic Feature Control