Passing filter to object page table – ABAP RAP Custom Entity
This blog explains how to apply user filter to not only list page but also in object page, especially to restrict data in the associated tables in object page.
Prerequisite:
The exercise application from my previous blog will be used. In this blog, we will extend this simple RAP application with multiple tables in object page. Please makes sure to complete the exersice in this previous blog before starting.
Multiple Facets in ABAP RAP Object Page with Custom Entity – SAP Extensibility 101
The setup
In the previous blog, we have created sales order list and in the object page we can view the sales order item data and scheduling line data.
Now let’s say user only wants to see all the sales order and scheduling line before certain date in the past. To do that, in this blog, we will add a filter ‘Key Date’. If user enters 2020.01.01, only sales order with confirmed delivery date before that should be displayed.
1. Adding filter field to root entity
In the root entity ZSALESDOC_C, add field ‘KEYDATE’ with date type. The most important part is that it has to be a key field to make the value pass down to the object page.
- UI.selectionField will make it display as user filter
- Hide it from list item as it’s not needed to show in the output
- Add label
- Key date will be single value parameter
define root custom entity ZSALESDOC_C
{
@UI.facet : [ { id: 'SalesDoc',
purpose: #STANDARD,
type : #IDENTIFICATION_REFERENCE,
label : 'Sales Document',
position: 10 },
{ id : 'LineItem',
purpose : #STANDARD,
type : #LINEITEM_REFERENCE,
label : 'Sales Doc Item',
position : 20,
targetElement: '_LineItem'},
{ id : 'ScheLine',
purpose : #STANDARD,
type : #LINEITEM_REFERENCE,
label : 'Schedule Line Item',
position : 30,
targetElement: '_ScheLine'}
]
@UI.lineItem : [{ position: 10 }]
@UI.selectionField : [{position: 10}]
@UI.identification : [{position: 10}]
key VBELN : vbeln_va;
@UI.selectionField : [{position: 20}]
@UI.lineItem : [{ hidden: true }]
@EndUserText.label : 'Key date'
@Consumption.filter:{ selectionType: #SINGLE}
key KEYDATE : abap.dats; // Used for filtering the Creation date and dates in object page. Needs to be key field to be passed to object page ABAP class
@UI.lineItem : [{ position: 20 }]
@UI.identification : [{position: 20}]
KUNNR : kunag;
@UI.lineItem : [{ position: 30 }]
@UI.identification : [{position: 30}]
AUART : auart;
@UI.lineItem : [{ position: 40 }]
@UI.identification : [{position: 40}]
ERDAT : erdat;
//Associations
_LineItem : composition [0..*] of ZSALESITEM_C;
_ScheLine : composition [0..*] of ZSALESSCHEDULE_C;
}
2. Applying filter to list page
Now to apply the filter to the output of list page, we need to do that in the ABAP class in root entity ZCL_SALESDOC.
- As KEYDATE is a key field in root entity, the value entered by user is stored in lt_conditions_range. Fetch the value of the first row as it is a single parameter.
- If the fitler is left empty, use current system date instead.
- Apply the key date to erdat(sales order creation date) getting only the sales order created before the key date.
CLASS zcl_salesdoc IMPLEMENTATION.
METHOD if_rap_query_provider~select.
DATA: lt_r_vbeln TYPE tt_range_option,
lt_r_keydate TYPE tt_range_option,
lv_keydate TYPE dats,
lv_count TYPE int8.
IF io_request->is_data_requested( ).
DATA(lv_parameter) = io_request->get_parameters( ).
DATA(lv_top) = io_request->get_paging( )->get_page_size( ).
IF lv_top < 0.
lv_top = 1.
ENDIF.
DATA(lv_skip) = io_request->get_paging( )->get_offset( ).
DATA(lt_sort) = io_request->get_sort_elements( ).
DATA : lv_orderby TYPE string.
LOOP AT lt_sort INTO DATA(ls_sort).
IF ls_sort-descending = abap_true.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } DESCENDING '|.
ELSE.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } ASCENDING '|.
ENDIF.
ENDLOOP.
IF lv_orderby IS INITIAL.
lv_orderby = 'vbak~vbeln'.
ENDIF.
*
* DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( ).
DATA(lt_conditions_range) = io_request->get_filter( )->get_as_ranges( ).
IF line_exists( lt_conditions_range[ name = 'VBELN' ] ).
lt_r_vbeln = lt_conditions_range[ name = 'VBELN' ]-range.
ENDIF.
IF line_exists( lt_conditions_range[ name = 'KEYDATE' ] ).
lt_r_keydate = lt_conditions_range[ name = 'KEYDATE' ]-range.
READ TABLE lt_r_keydate ASSIGNING FIELD-SYMBOL(<lw_r_keydate>) INDEX 1.
lv_keydate = <lw_r_keydate>-low.
ELSE.
lv_keydate = sy-datum. "Todays date if no filter value is entered
ENDIF.
SELECT DISTINCT
vbak~vbeln,
vbak~erdat,
vbak~auart,
vbak~kunnr,
@lv_keydate AS keydate "Pass the filter value to object page
FROM vbak
INNER JOIN kna1
ON vbak~kunnr = kna1~kunnr
INNER JOIN vbap
ON vbap~vbeln = vbak~vbeln
WHERE vbak~vbeln IN @lt_r_vbeln
AND vbak~erdat <= @lv_keydate "Get all data before the key date
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_vbak)
UP TO @lv_top ROWS OFFSET @lv_skip.
"Get the total number of records
SELECT DISTINCT
vbak~vbeln,
vbak~erdat,
vbak~auart,
vbak~kunnr,
@lv_keydate AS keydate "Pass the filter value to object page
FROM vbak
INNER JOIN kna1
ON vbak~kunnr = kna1~kunnr
INNER JOIN vbap
ON vbap~vbeln = vbak~vbeln
WHERE vbak~vbeln IN @lt_r_vbeln
AND vbak~erdat <= @lv_keydate "Get all data before the key date
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_vbak_count).
lv_count = lines( lt_vbak_count ).
io_response->set_total_number_of_records( lv_count ). "Set the max total count of rows expected in the list report.
io_response->set_data( lt_vbak ).
ENDIF.
ENDMETHOD.
3. Adding filter field to child entity
Now the filter field KEYDATE must be added to the child entity ZSALESSCHEDULE_C, as it’s the Delivery Date in scheduling line entity that we want to restrict with KEYDATE.
- Add the same field name and same type
- Does not have to be key field in the child entity as the value doesn’t need to be passed from the child entity to anywhere else.
- Hide from output
- Add KETDATE to join condition to root entity
define custom entity ZSALESSCHEDULE_C
{
@UI.facet : [ { id: 'LineItem',
purpose : #STANDARD,
type : #IDENTIFICATION_REFERENCE,
label : 'Schedule Line Items',
position : 10 } ]
@UI.hidden: true
key vbeln : vbeln_va;
@UI.lineItem : [{ position: 10 }]
@UI.identification : [{position: 10}]
key posnr : posnr_va;
@UI.lineItem : [{ position: 20 }]
@UI.identification : [{position: 20}]
key etenr : etenr;
@UI.lineItem : [{ position: 30 }]
@UI.identification : [{position: 30}]
edatu : edatu;
@UI.lineItem : [{ position: 40 }]
@UI.identification : [{position: 40}]
@Semantics: { quantity : {unitOfMeasure: 'vrkme' } }
wmeng : wmeng;
@UI.lineItem : [{ position: 50 }]
@UI.identification : [{position: 50}]
@Semantics: { quantity : {unitOfMeasure: 'vrkme' } }
bmeng : bmeng;
@UI.lineItem : [{ position: 60 }]
@UI.identification : [{position: 60}]
vrkme : vrkme;
@UI.hidden: true
keydate : abap.dats; // Used for filtering the object page. Does not need to be key field here in object page
_SalesDoc : association to parent ZSALESDOC_C on $projection.vbeln = _SalesDoc.VBELN
and $projection.keydate = _SalesDoc.KEYDATE;
}
4. Applying filter to object page
Now to apply the filter to the object page output of sales order scheduling line, we need to do that in the ABAP class in root entity ZCL_SALESSCHEDULE.
The logic is the same as in ZCL_SALESDOC except it’s applied to delivery date in the scheduling line. It’s also not required in the SQL output and in returning date.
CLASS zcl_salesschedule IMPLEMENTATION.
METHOD if_rap_query_provider~select.
DATA: lt_r_vbeln TYPE tt_range_option,
lt_r_keydate TYPE tt_range_option,
lv_keydate TYPE dats,
lv_count TYPE int8.
IF io_request->is_data_requested( ).
DATA(lv_parameter) = io_request->get_parameters( ).
DATA(lv_top) = io_request->get_paging( )->get_page_size( ).
IF lv_top < 0.
lv_top = 1.
ENDIF.
DATA(lv_skip) = io_request->get_paging( )->get_offset( ).
DATA(lt_sort) = io_request->get_sort_elements( ).
DATA : lv_orderby TYPE string.
LOOP AT lt_sort INTO DATA(ls_sort).
IF ls_sort-descending = abap_true.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } DESCENDING '|.
ELSE.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } ASCENDING '|.
ENDIF.
ENDLOOP.
IF lv_orderby IS INITIAL.
lv_orderby = 'vbap~vbeln, vbap~posnr, vbep~etenr'.
ENDIF.
*
* DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( ).
DATA(lt_conditions_range) = io_request->get_filter( )->get_as_ranges( ).
IF line_exists( lt_conditions_range[ name = 'VBELN' ] ).
lt_r_vbeln = lt_conditions_range[ name = 'VBELN' ]-range.
ENDIF.
IF line_exists( lt_conditions_range[ name = 'KEYDATE' ] ).
lt_r_keydate = lt_conditions_range[ name = 'KEYDATE' ]-range.
READ TABLE lt_r_keydate ASSIGNING FIELD-SYMBOL(<lw_r_keydate>) INDEX 1.
lv_keydate = <lw_r_keydate>-low.
ELSE.
lv_keydate = sy-datum. "Todays date if no filter value is entered
ENDIF.
SELECT
FROM vbap
INNER JOIN vbep
ON vbap~vbeln = vbep~vbeln
AND vbap~posnr = vbep~posnr
FIELDS vbap~vbeln,
vbap~posnr,
vbep~etenr,
vbep~edatu,
vbep~wmeng,
vbep~bmeng,
vbep~vrkme
WHERE vbap~vbeln IN @lt_r_vbeln
AND vbep~edatu <= @lv_keydate "Get all data before the key date
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_vbep)
UP TO @lv_top ROWS OFFSET @lv_skip.
"Get the total number of records
SELECT
FROM vbap
INNER JOIN vbep
ON vbap~vbeln = vbep~vbeln
AND vbap~posnr = vbep~posnr
FIELDS vbap~vbeln,
vbap~posnr,
vbep~etenr,
vbep~edatu,
vbep~wmeng,
vbep~bmeng,
vbep~vrkme
WHERE vbap~vbeln IN @lt_r_vbeln
AND vbep~edatu <= @lv_keydate "Get all data before the key date
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_vbep_count).
IF io_request->is_data_requested( ).
io_response->set_data( lt_vbep ).
ENDIF.
IF io_request->is_total_numb_of_rec_requested( ).
io_response->set_total_number_of_records( lines( lt_vbep_count ) ).
ENDIF.
ENDIF.
ENDMETHOD.
5. App preview
Now preview the app and you can see the Key Date as a filter. Let’s test with sales order 6 with creation date Nov 20, 2015 and three dcheduling lines with delivery dates “Nov 20, 2015”, “Apr 25, 2022” and “Dec 4, 2015”.
Now let’s enter a key date “Nov 20, 2015” in the filter. You can see that sales order 6 is in the list page output.
Click on sales order 6 and in the object page, you can see the scheduling line is restricted with the key date as well.
One Reply to “Passing filter to object page table – ABAP RAP Custom Entity”
Comments are closed.