Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
At CRM system, when you need to maintain the content of a decision table at Business Rule Framework plus, could be a requirement, during the activation action, to identify the changes done by the user.

For this, we need to compare the changes that the user has done on the table content at the decision table settings screen with the content stored on the database.

After press the "Activate" button, an object of the exit class registered on the application is instantiated. On this instance, we can check the differences, identifying the rows that have been modified by the user.



 

After implementation, when you change the table content of a decision table linked to the application where the exit class have been registered, the method ACTIVATION_VETO wil be triggered when the "Activate" button is pressed, on the decision table settings screen.

On this method, you can read the content of the screen and the content that is already saved on the database, making checks accordingly with your requirements.

 

Implementation

Create a class for the interface IF_FDT_APPLICATION_SETTINGS on T-CODE SE24.

Implement the method ACTIVATION_VETO.



Ps.: the method is only triggered whether the CONSTRUCTOR is implemented as static and attribute GV_ACTIVATION_VETO setted to ABAP_TRUE.

 

Take note of the application ID:



 

On the application settings we should link the created class to the application on BRFPLUS:



 

At T-CODE SE11, create:

Structure Z_S_DECISION_TABLE_RANGE



 

Table Type Z_TT_DECISION_TABLE_RANGE



 

Structure Z_S_DECISION_TABLE_DATA



 

Source code:
METHOD if_fdt_application_settings~activation_veto.

TYPES: BEGIN OF ty_decision_table_string,
decision_table_id TYPE <Decision table ID>,
ts_tange_low TYPE string,
r_value TYPE string,
END OF ty_decision_table_string.

DATA: lt_decision_table_str TYPE TABLE OF ty_decision_table_string,
ls_decision_table_str TYPE ty_decision_table_string,
lt_decision_table_str_old TYPE TABLE OF ty_decision_table_string,
ls_decision_table_str_old TYPE ty_decision_table_string,
lref_decision_table TYPE REF TO cl_fdt_decision_table,
lref_factory TYPE REF TO if_fdt_factory,
lr_data TYPE REF TO data,
lt_decision_table TYPE TABLE OF z_s_decision_table_data,
ls_decision_table LIKE LINE OF lt_decision_table,
lt_decision_table_old TYPE TABLE OF z_s_decision_table_data,
ls_decision_table_old LIKE LINE OF lt_decision_table,
lv_timestamp TYPE timestamp,
lv_col_no TYPE int4,
lt_decision_table_id TYPE TABLE OF <Decision table ID>.

FIELD-SYMBOLS: <fs_decision_table_id> TYPE any.

" GUID of application
CONSTANTS: co_app_id_ctt_product_rules TYPE if_fdt_types=>id VALUE '<Application ID>'.

*********************************************************************************************************************************

GET TIME STAMP FIELD lv_timestamp.

" Generic factory instance
lref_factory = cl_fdt_factory=>if_fdt_factory~get_instance( co_app_id_ctt_product_rules ).

" Get the expression instance of the decision table with the object ID
lref_decision_table ?= lref_factory->get_expression( iv_id = iv_id ).

" Get the decision table data based on above expression GUID
" it means that it will read the data including the user's changes before the activation
lref_decision_table->if_fdt_decision_table~get_table_data( IMPORTING ets_data = DATA(ets_data) ).

lt_decision_table = ets_data.
SORT lt_decision_table BY col_no row_no.
CHECK lt_decision_table IS NOT INITIAL.

" Transform the decision table on a string table to be possible to compare the content with the data that is stored on the database
DATA(lv_end_of_loop) = abap_false.

WHILE lv_end_of_loop = abap_false.
lv_col_no = lv_col_no + 1.

LOOP AT lt_decision_table INTO ls_decision_table WHERE col_no = lv_col_no.
DATA(ls_range) = COND #( WHEN line_exists( ls_decision_table-ts_range[ 1 ] )
THEN ls_decision_table-ts_range[ 1 ] ).

lr_data = ls_range-r_low_value.
ASSIGN lr_data->* TO FIELD-SYMBOL(<fs_ts_range_low>).

IF <fs_ts_range_low> IS ASSIGNED.
" The ROW_NO 1 stores the decision table ID
IF ls_decision_table-row_no = 1.
ls_decision_table_str-decision_table_id = <fs_ts_range_low>.
ELSE.
ls_decision_table_str-ts_tange_low = ls_decision_table_str-ts_tange_low && ls_range-option && <fs_ts_range_low>.
ENDIF.
UNASSIGN <fs_ts_range_low>.
ENDIF.

lr_data = ls_decision_table-r_value.
ASSIGN lr_data->* TO FIELD-SYMBOL(<fs_r_value>).

IF <fs_r_value> IS ASSIGNED.
ls_decision_table_str-r_value = ls_decision_table_str-r_value && <fs_r_value>.
UNASSIGN <fs_r_value>.
ENDIF.
ENDLOOP.

IF sy-subrc NE 0.
lv_end_of_loop = abap_true.
CLEAR lv_col_no.
ELSE.
APPEND ls_decision_table_str TO lt_decision_table_str.
CLEAR ls_decision_table_str.
ENDIF.
ENDWHILE.

" Get the decision table data based on above expression GUID and the current timestamp
" it means that it will read the data saved on the database
lref_decision_table->if_fdt_decision_table~get_table_data( EXPORTING iv_timestamp = lv_timestamp
IMPORTING ets_data = DATA(ets_data_old) ).

lt_decision_table_old = ets_data_old.
SORT lt_decision_table_old BY col_no row_no.
CHECK lt_decision_table_old IS NOT INITIAL.

" Transform the decision table on a string table to be possible to compare the content with the data with the user's changes before the activation
lv_end_of_loop = abap_false.

WHILE lv_end_of_loop = abap_false.
lv_col_no = lv_col_no + 1.

LOOP AT lt_decision_table_old INTO ls_decision_table_old WHERE col_no = lv_col_no.
DATA(ls_range_old) = COND #( WHEN line_exists( ls_decision_table_old-ts_range[ 1 ] )
THEN ls_decision_table_old-ts_range[ 1 ] ).

lr_data = ls_range_old-r_low_value.
ASSIGN lr_data->* TO <fs_ts_range_low>.

IF <fs_ts_range_low> IS ASSIGNED.
" The ROW_NO 1 stores the decision table ID
IF ls_decision_table_old-row_no = 1.
ls_decision_table_str_old-decision_table_id = <fs_ts_range_low>.
ELSE.
ls_decision_table_str_old-ts_tange_low = ls_decision_table_str_old-ts_tange_low && ls_range_old-option && <fs_ts_range_low>.
ENDIF.
UNASSIGN <fs_ts_range_low>.
ENDIF.

lr_data = ls_decision_table_old-r_value.
ASSIGN lr_data->* TO <fs_r_value>.

IF <fs_r_value> IS ASSIGNED.
ls_decision_table_str_old-r_value = ls_decision_table_str_old-r_value && <fs_r_value>.
UNASSIGN <fs_r_value>.
ENDIF.
ENDLOOP.

IF sy-subrc NE 0.
lv_end_of_loop = abap_true.
CLEAR lv_col_no.
ELSE.
APPEND ls_decision_table_str_old TO lt_decision_table_str_old.
CLEAR ls_decision_table_str_old.
ENDIF.
ENDWHILE.

*********************************************************************************************************************************

" Check differences between the internal tables
" and removes the content that have not been changed
LOOP AT lt_decision_table_str_old INTO ls_decision_table_str_old.
DATA(lv_tabix) = sy-tabix.

READ TABLE lt_decision_table_str WITH KEY decision_table_id = ls_decision_table_str_old-decision_table_id
r_value = ls_decision_table_str_old-r_value
ts_tange_low = ls_decision_table_str_old-ts_tange_low
INTO ls_decision_table_str.

IF sy-subrc = 0.
DELETE lt_decision_table_str INDEX sy-tabix.
DELETE lt_decision_table_str_old INDEX lv_tabix.
ENDIF.
ENDLOOP.

APPEND LINES OF lt_decision_table_str_old TO lt_decision_table_str.
SORT lt_decision_table_str BY decision_table_id ASCENDING.
DELETE ADJACENT DUPLICATES FROM lt_decision_table_str COMPARING decision_table_id.

" Fill table with the ID of the rows that have been modified
LOOP AT lt_decision_table_str INTO ls_decision_table_str.
APPEND ls_decision_table_str-decision_table_id TO lt_decision_table_id.
ENDLOOP.
ENDMETHOD.
3 Comments
Labels in this area