Technical Articles
SAP ABAP Programming Model for FIORI- List Report Application (Part 2)
Hello All,
This is the second blog in this series. You can refer to the first blog in the below link:
SAP ABAP Programming Model for FIORI- List Report Application (Part 1)
In this blog we will be looking into BOPF part to enable the Determination, Validation and Action in our Fiori List report Application:
Let’s proceed with this tutorial. In last blog we have created a Transaction CDS on SPFLI Table.
Go to the CDS View and click on the highlighted dot, and then the link for the Generated BOPF Object as shown in below image:
BOPF Path
The Generated Business Object will look as below. Click on ‘Go to Root Node’:
In the root Node we can see option to Navigate for Determination, Action and Validation
BOPF Root Node
Determination: It can be use to determine some value at runtime. In our case we are using it to generate the Primary key value at runtime.
To create a new Determination, click on the Determination link in above image and then click on ‘New’ Button.
Once created click on ‘Triggers Configured’ and enable it for create and update. You can also see the generated class for this determination where we will be writing our code:
Now go into the generated class and write the below code:
class ZCL_IDEMO_D_CALCULATEKEYVALUES definition
public
inheriting from /BOBF/CL_LIB_D_SUPERCL_SIMPLE
final
create public .
public section.
methods /BOBF/IF_FRW_DETERMINATION~EXECUTE
redefinition .
protected section.
private section.
ENDCLASS.
CLASS ZCL_IDEMO_D_CALCULATEKEYVALUES IMPLEMENTATION.
METHOD /bobf/if_frw_determination~execute.
"Read data with the given keys (typed with combined type table)
DATA lt_data TYPE ztidemo_ddl_spfli.
"Call retrieve method of BOPF Framework
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key " uuid of node name
it_key = it_key " keys given to the determination
IMPORTING
eo_message = eo_message " pass message object
et_data = lt_data " itab with node data
et_failed_key = et_failed_key " pass failures
).
IF eo_message IS NOT BOUND.
eo_message = /bobf/cl_frw_factory=>get_message( ).
ENDIF.
"Select Data from DB Table
SELECT FROM spfli
FIELDS carrid, MAX( connid ) AS max
GROUP BY carrid
INTO TABLE @DATA(lt_max_item).
" Assign numbers to each newly created item and trigger the modification in BOPF
LOOP AT lt_data REFERENCE INTO DATA(lr_data).
IF lr_data->connid IS INITIAL.
"As the field is read only it will be always Initial in our case
READ TABLE lt_max_item WITH KEY carrid = lr_data->parent_key REFERENCE INTO DATA(lr_max_item).
IF sy-subrc = 0.
lr_max_item->max = lr_max_item->max + 10.
ELSE.
"Assign an Incremented value. In real case scenario we can get the new number from number range "function
APPEND INITIAL LINE TO lt_max_item REFERENCE INTO lr_max_item.
lr_max_item->max = lr_data->parent_key.
lr_max_item->max = lt_max_item[ carrid = 'AA' ]-max + 1 .
lr_max_item->carrid = 'AA'.
ENDIF.
" Fill leading zeros for ALPHANUM field on database
lr_data->carrid = lr_max_item->carrid.
lr_data->connid = |{ lr_max_item->max ALPHA = IN }|.
lr_data->arrtime = sy-uzeit.
lr_data->deptime = sy-uzeit.
io_modify->update(
EXPORTING
iv_node = is_ctx-node_key " uuid of node
iv_key = lr_data->key " key of line
is_data = lr_data " ref to modified data
it_changed_fields =
VALUE #( ( zif_idemo_ddl_spfli_c=>sc_node_attribute-zidemo_ddl_spfli-carrid )
( zif_idemo_ddl_spfli_c=>sc_node_attribute-zidemo_ddl_spfli-connid )
( zif_idemo_ddl_spfli_c=>sc_node_attribute-zidemo_ddl_spfli-arrtime )
( zif_idemo_ddl_spfli_c=>sc_node_attribute-zidemo_ddl_spfli-deptime )
( zif_idemo_ddl_spfli_c=>sc_node_attribute-zidemo_ddl_spfli-fltype )
)
). "Here you have to pass all the field name which you change or passing value
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Similarly create a new Validation by clicking on the Validation link under the root node. You can refer below image for the generated Validation:
BOPF Validation
Validation: Validation are use to validate the Input Screen data.
In our case we are validating the Country From Field.
I have created a Message class with below messages-
Message Class
Go to the generated validation class and write down the below code:
CLASS zcl_idemo_v_validatecountry DEFINITION
PUBLIC
INHERITING FROM /bobf/cl_lib_v_supercl_simple
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS /bobf/if_frw_validation~execute
REDEFINITION .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_IDEMO_V_VALIDATECOUNTRY IMPLEMENTATION.
METHOD /bobf/if_frw_validation~execute.
" Internal tab for Header Data
" Created using reference to Generated Table Type
DATA(lt_head) = VALUE ztidemo_ddl_spfli( ).
" Get Header Data row under process
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key " Node Name
it_key = it_key " Key Table
IMPORTING
et_data = lt_head " Data Return Structure
).
" Instantiate Message Object if not bound
IF eo_message IS NOT BOUND.
eo_message = /bobf/cl_frw_factory=>get_message( ).
ENDIF.
"Loop the fetched records
LOOP AT lt_head REFERENCE INTO DATA(lr_head).
" Validate
DATA ls_msg TYPE symsg.
"If Country From is blank raise an error
IF lr_head->countryfr IS INITIAL.
ls_msg-msgty = 'E'.
ls_msg-msgid = 'ZBOPF'.
ls_msg-msgno = '000'.
ELSE.
"If entered Country is not valid raise an error
SELECT COUNT(*) FROM t005 INTO @DATA(lv_count) WHERE land1 = @lr_head->countryfr.
IF lv_count = 0.
ls_msg-msgty = 'E'.
ls_msg-msgid = 'ZBOPF'.
ls_msg-msgno = '001'.
ENDIF.
ENDIF.
" Add Message
IF NOT ls_msg IS INITIAL.
eo_message->add_message(
EXPORTING
is_msg = ls_msg " Message
iv_node = is_ctx-node_key " Node
iv_key = lr_head->key " Instance key
).
"Below step is important to stop the flow when error occurs
DATA ls_key TYPE /bobf/s_frw_key.
ls_key-key = lr_head->key.
APPEND ls_key TO et_failed_key.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
In Case if Validation fails, the create or update process will not get complete and error will appear on the FIORI App screen as shown below:
Validation Errors
Finally we will be adding the Action to our BOPF:
Action: Usually we use it to perform some activity based on some event which cannot be handled in create, update or delete methods.
In our case we are creating a new record by referring to the selected one. The Action button is added to the UI view with the help of annotation mentioned in the Metadata Extension view for SPFLI.
To create a Action we need to navigate to the root node for the generated Business Object of SPFLI (Shown in the image earlier) and click on the Action link.
Click on the ‘New’ Button in next page and create new Action referring to the below Image.(Note that the Action Name should match to the dataAction Value mentioned in the Metadata Extension view file).
CLASS zcl_idemo_a_copy DEFINITION
PUBLIC
INHERITING FROM /bobf/cl_lib_a_supercl_simple
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS /bobf/if_frw_action~execute
REDEFINITION .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_idemo_a_copy IMPLEMENTATION.
METHOD /bobf/if_frw_action~execute.
DATA: lr_head_ref TYPE REF TO data.
DATA(lt_head) = VALUE ztidemo_ddl_spfli( ).
DATA ls_head_ref TYPE zsidemo_ddl_spfli.
" Retrieve the data from the Node
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key
it_key = it_key
IMPORTING
et_data = lt_head
).
"Copy the data from retrieved node
LOOP AT lt_head REFERENCE INTO DATA(lr_head).
ASSIGN lr_head->* TO FIELD-SYMBOL(<fs_head>).
ls_head_ref-carrid = <fs_head>-carrid.
"Increase the connection id by 10 to avoid the primary key violation error
ls_head_ref-connid = <fs_head>-connid + 10.
"Date and time cannot be kept blank else the OData Metadata will fail to load
ls_head_ref-arrtime = sy-uzeit.
ls_head_ref-deptime = sy-uzeit.
ls_head_ref-countryfr = <fs_head>-countryfr.
"Copy field data
CREATE DATA lr_head_ref TYPE zsidemo_ddl_spfli.
ASSIGN lr_head_ref->* TO FIELD-SYMBOL(<fs_head_ref>).
IF <fs_head_ref> IS ASSIGNED.
<fs_head_ref> = ls_head_ref.
ENDIF.
"Create Record
io_modify->create(
EXPORTING
iv_node = is_ctx-node_key
is_data = lr_head_ref
IMPORTING
ev_key = DATA(lv_copy_key)
).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
So here we are completed with this blog. We have successfully added the Determination, Validation and Action Node behavior to our BOPF. In the next blog we will see how to finally consume this view as a Fiori Application using SAP WebIDE.
SAP ABAP Programming Model for FIORI- List Report Application (Part 3)
Thanks,
Amit Diwane
Hello,
Very interesting and complete blog.
Usually the creation of documents, items in SAP is done through Bapi, function module. Database table is never updated directly. It seems that with Bopf, the table is updated directly. Is there a way to use a Bapi?
Thank you.
Christophe.
Hello Christophe,
Thanks for your comment. Although I never tried calling the BAPI within BOPF but you can create an Action where you will read all the Header and Item data (retrieve it by association) and then call the BAPI.
Thanks,
Amit Diwane
Hi Amit, This was a nice blog indeed. I was able to call a BAPI in a Determination on Fiori List report Save action. The BAPI working fine and able to create a new record as expected.
My issue is, I am unable to show the BOPF return message after the Object page "Save" action. Do you have any insight on this? I raised the message using the eo_message parameter and I can see the message at the browser response (F12) when I do the "save" action. But its not just showing in the app.
Thank
Angshuman
Hello Angshuman,
Thanks letting us know that BAPI works with Determination. I tried passing the message in the determination class ZCL_IDEMO_D_CALCULATEKEYVALUES. The code is below for your reference. This code I added at the end of the method execute.
Hi Angshuman,
If incase we use determination, do we need separately annotate the determination name in the CDS Consumption View?
Can you please share your consumption view code?
Hi
We don't need separate annotations for determination. The Object model annotation will create the BOPF. Inside BOPF you can create a determination class (either in eclipse or in transaction BOBX).
The objectModel annotation the BOPF screenshot attached below.
Click on New to create New determination Class in eclipse
Very Nice blog
Hello Amit,
Nice blog.
Please note that the ABAP RESTful Application Programming Model (RAP) is the evolutionary successor of the BOPF-based ABAP Programming Model for SAP Fiori.
More information can be found here:
Kind regards,
Carine
Hi Amit,
Nice Blog.
I followed steps can able to see Action button but when i tried to trigger action by selecting the record respective action class is not triggering but when i tested from Generated Business Object the class is triggering is anything missed.
Thanks.
Hello @Rakesh Gowdru,
I guess you might have missed the annotations on the CDS end. Also make sure the dataAction name matches with BOPF method name.
It is really a great article and helped me a lot. I just started to work with CDS views and I was able to reproduce and understand everything what was explained here. I am just asking myself if it would be possible to mark the fields which are not filled or not correctly filled in red and set error message beside this fields.
Hello Björn Kron ,
Glad to know this blog series helped you. Regarding your query you can mark the field as Mandatory in the CDS Metadata.
Hope this helps.
Regards,
Amit Diwane