Enhance the Business Object Behavior With Factory Action
- How to define factory action
- How to implement factory action
- How to preview and test enhanced travel app
Prerequisites
- You need to have access to an SAP BTP, ABAP environment, or SAP S/4HANA Cloud, ABAP environment or SAP S/4HANA (release 2021 or higher) system.
For example, you can create free trial user on SAP BTP, ABAP environment. - You have downloaded and installed the latest ABAP Development Tools (ADT) on the latest Eclipse© platform.
In the previous exercise, you’ve defined and implemented instance action.
In the present exercise, you will learn how to add factory action.
Reminder: Do not forget to replace the suffix placeholder ### with your chosen or assigned group ID in the exercise steps below.
About: Actions:
In the RAP context, an action is a non-standard operation that change the data of a BO instance. They are self-implemented operations.
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. If the optional keywordstatic
is used, the action is defined as static action. Static actions are not bound to any instance of a RAP BO entity but relate to the complete entity.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 | Implicit Response Parameters | ABAP EML -
response_param
- Step 1
Now, you will define, implement, and expose the action
copyTravel
, an instance-bound factory action used to copy one or more travel 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-
Go to the behavior definition
ZRAP100_R_TRAVELTP_###
and insert the following code snippet after the action defined in the previous step.ABAPCopyfactory 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.
Further information can be found here: CDS BDL - action, factory
-
Save
and activatethe changes.
Log in to complete tutorial -
- Step 2
Implement the instance factory action
coyTravel
in the base BO behavior pool.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 actioncopyTravel
of entityzrap100_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 pool class iconZRAP100_BP_TRAVELTP_###
. 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 transferred 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 needed.- 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 new travel instances to Open (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 table mapped-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.
ABAPCopy************************************************************************** * 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.
The result should look like this:
Save
and activatethe changes.
Log in to complete tutorial - Step 3
Expose the instance factory action in the BO behavior projection and in the CDS metadata extension and test the enhance SAP Fiori elements app.
Expose the new action
copyTravel
in the BO behavior projection. For that, open your behavior projectionZRAP100_C_TRAVELTP_###
and insert the following code snippet after the actions added previously.ABAPCopyuse action copyTravel;
The result should like this:
Save
and activatethe changes.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 extensionZRAP100_C_TRAVELTP_###
and un-comment following code line in the@UI.lineItem
annotation block placed before the elementOverallStatus
.ABAPCopy,{ type: #FOR_ACTION, dataAction: 'copyTravel', label: 'Copy Travel' }
The result should look like this:
Save
and activatethe changes.Preview and test the enhanced SAP Fiori elements app. Select a travel instance and choose Copy.
An object page with the new travel instance opens.
Log in to complete tutorial - Step 4
In this step, you will define, implement, and expose two instance-bound non-factory actions for the Travel entity,
acceptTravel
andrejectTravel
. These actions will be used to set the overall status of one or more given travel instances to accepted (A) and rejected (X) respectively.First, define the instance non-factory actions
acceptTravel
andrejectTravel
in the behavior definition of the travel entity.
Go to your behavior definitionZRAP100_R_TRAVELTP_###
and define both actions.For that, insert the following code snippet after the defined validations as shown on the screenshot below.
ABAPCopyaction acceptTravel result [1] $self; action rejectTravel result [1] $self;
The result should like this:
Save
and activatethe changes.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 entityzrap100_r_traveltp_###
to add both methods to thelocal handler class lcl_handler
of the behavior poolZRAP100_BP_TRAVELTP_###
.The result should look like this:
You are through with the definition of both actions. Go ahead with the implementations of the two inserted method in the behavior pool.
Log in to complete tutorial - Step 5
Now implement the required action methods in the behavior pool
ZRAP100_BP_TRAVELTP_###
of the travel entity.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.
ABAPCopy************************************************************************************* * 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.
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 paramter result.
Implement the action
rejectTravel
which is used to set the value of the fieldOverallStatus
to rejected (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.ABAPCopy************************************************************************************* * 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.
Save
and activatethe changes.
Log in to complete tutorial - Step 6
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.
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.ABAPCopyuse action acceptTravel; use action rejectTravel;
Your source code should look like this:
Save
and activatethe 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 and reject 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.Save
and activatethe changes.You can now preview and test your enhanced SAP 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.
Log in to complete tutorial