How to add custom project element filters in SAP Portfolio and Project Management
As a continuation of my How-To series for custom development in the area of SAP PPM:
- How to work with field conditions in SAP Portfolio and Project Management
- How to add transient fields in SAP Portfolio and Project Management
- How to add custom tabs with fields from standard tables in SAP Portfolio and Project Management
After we successfully added a custom field on the task element (as described in my previous tutorial), we now want to be able to filter the project elements by such a custom field.
Exanple: We added a checkbox to mark if a task is a billing element.
And now we want to be able to use the filter functionality within the project to search for all tasks that are marked as billing elements.
1. Data dictionary enhancements
First, we need to add the new filter as a custom field in structure DPR_TS_UI_TABLE_FILTER_CRIT. This structure used in the UI to generate the layout as well and then passed to the UI logic classes to enable the filtering.
Note: For this purpose, the PPM frameworks offers a customer include. If not existing, this might need to be created in your system.
For simplicity reasons, we will add the filter with the same name:
2. Enhancing the User Interface
2.1. If not existing, we need to create an enhancement for Web Dynpro component DPR_MPMON_FILTER. Then add the new attribute to both context nodes CRITERIA and FILTER_ADM_CRITERIA:
Here the newly added ZZ* field(s) should already be visible:
Note: There are two different nodes for the filter criteria as PPM offers the option to save complex filter conditions. As all standard fields are included in this functionality, we want to enable this for our custom filter as well.
2.2. Navigate to the context tab of view VI_FILTER_CRITERIA and update the mappings of both nodes CRITERIA and FILTER_ADM_CRITERIA:
The attribute ZZBILLING_ELEMENT should now be visible when expanding the nodes.
2.3. Go to the Layout tab and add the actual checkbox field under the following path:
ROOTUIELEMENTCONTAINER > TCR_FILTER > TCR_MAIN_CRITERIA
In this example, we will add a checkbox field under the Tasks subsection next to the Milestone checkbox:
2.4. Now repeat this procedure and add the same checkbox under the following path:
ROOTUIELEMENTCONTAINER > TCR_SAV_FILTER > TCR_MAIN_CRITERIA_CP
Note: You can also copy and paste the previously defined checkbox and simply switch the binding of property checked to point to node FILTER_ADM_CRITERIA.
That’s it for the UI enhancements. If you open the filter dialog you should already be able to see the new checkbox. Now let’s implement the logic behind the new filter.
3. Implementing the filter check
3.1. Create an explicit enhancement to class CL_DPR_MPMON_FILTER. Then define a new method for the filter check:
Here is a sample implementation:
METHOD zzcheck_billing_element. DATA: lo_task TYPE REF TO cl_dpr_task_o, ls_task_int TYPE dpr_ts_task_int. mv_add_current_elem_to_result = abap_false. " Only proceed if element is a task. CHECK mv_current_element-object_type = cl_dpr_co=>sc_ot_task. lo_task ?= cl_dpr_api_services=>get_object_by_guid( mv_current_element-guid ). lo_task->get_data_ext( IMPORTING es_task_int = ls_task_int ). IF ls_task_int-zzbilling_element = abap_true. mv_add_current_elem_to_result = abap_true. ENDIF. ENDMETHOD.
Note: Here the class attribute MV_CURRENT_ELEMENT will be filled at runtime – even though this has the prefix MV, it is actually a structure containing some of the element attributes. As a result of this method, we need to fill class attribute MV_ADD_CURRENT_ELEM_TO_RESULT.
3.2. Optional: Define a constant for the newly added check method:
Tip: This is not really required, but it is consistent with the standard implementation and will simplify maintenance later on.
3.3. All check methods must be added to static attribute ST_CHECK_METHOD_ASSIGNMENT. For the standard ones, these are added in the CLASS_CONSTRUCTOR method. Unfortunately, it is not possible to create pre-/post exits to this method. So to enable this, we need to create an implicit enhancement to this method and add the following code:
ls_asgn-method_name = zzcv_chk_meth_billing_elem. ls_asgn-obj_type = cl_dpr_co=>sc_ot_task. INSERT ls_asgn INTO TABLE st_check_method_assignment. ls_reqd-method_name = zzcv_chk_meth_billing_elem. ls_reqd-details = abap_true. ls_reqd-responsibles = abap_false. ls_reqd-status = abap_false. ls_reqd-severity = abap_false. INSERT ls_reqd INTO TABLE st_check_method_required_data.
3.4. We need to activate the check method when required. For this we need to create a Post-Exit enhancement to method COLLECT_METHODS:
CLASS lcl_zcl_dpr_mpmon_filter DEFINITION DEFERRED. CLASS cl_dpr_mpmon_filter DEFINITION LOCAL FRIENDS lcl_zcl_dpr_mpmon_filter. CLASS lcl_zcl_dpr_mpmon_filter DEFINITION. PUBLIC SECTION. CLASS-DATA obj TYPE REF TO lcl_zcl_dpr_mpmon_filter. "#EC NEEDED DATA core_object TYPE REF TO cl_dpr_mpmon_filter . "#EC NEEDED INTERFACES IPO_ZCL_DPR_MPMON_FILTER. METHODS: constructor IMPORTING core_object TYPE REF TO cl_dpr_mpmon_filter OPTIONAL. ENDCLASS. CLASS lcl_zcl_dpr_mpmon_filter IMPLEMENTATION. METHOD constructor. me->core_object = core_object. ENDMETHOD. METHOD ipo_zcl_dpr_mpmon_filter~collect_methods. *"------------------------------------------------------------------------* *" Declaration of POST-method, do not insert any comments here please! *" *"methods COLLECT_METHODS . *"------------------------------------------------------------------------* IF core_object->ms_filter_conditions-zzbilling_element = abap_true. core_object->activate_check_method( core_object->zzcv_chk_meth_billing_elem ). ENDIF. ENDMETHOD. ENDCLASS.
Basically, if the Billing Element checkbox is enabled in the filter dialog, then the newly added check method should be executed.
Opening the Project Management application, we can now filter for tasks where the billing element property is set:
The result list will contain only the tasks where the Billing Element is set to true, as well as the project phases and project definition.
Note: Although this is a simple example where the filter is 1-to-1 with a task attribute, this mechanism enables you to create complex filters as well.