This article just offers a small fast food program comparing parameters between two users. Some transactions use bunch of these params. During a tuning of a new user or in case of troubles is handy to compare them.
I was surprised that SUIM tx. does not offer such functionality. To keep all the comparison abilities on one place, I placed there buttons calling SUIM comparison tools too.
Because we use also an other PARID/PARVA based custom table with the same structure as USR05, I placed an option also to compare such table. You can add there as much radio buttons as you want.
How does it look like?
Input screen
Result screen
- Red - parameter exists just on one side
- Yellow - parameter exists on both sides, but the actual value differs
- Green - parameter exists on both sides and the value fits
Sorted by Parameter ID
Sorted by equality status
The source code:
*&---------------------------------------------------------------------*
*& Report Y_USER_CMP
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT y_user_cmp
.
TYPES: BEGIN OF sty_param_both
.
TYPES: parid
TYPE memoryid
. " ID line including both sides, used later for sorting
TYPES: parid1
TYPE abap_bool
.
TYPES: parva1
TYPE xuvalue
.
TYPES: parid2
TYPE abap_bool
. " The second id has to be stored as well because we need to distinguish the case where id is present within both tables, but empty on one side
TYPES: parva2
TYPE xuvalue
.
TYPES: partext
TYPE as4text
.
TYPES: status
TYPE c LENGTH
1. " S = successfull comparison, E = id not exists on both sides, W = ID exists but values differ
TYPES: t_color
TYPE lvc_t_scol
.
TYPES: END OF sty_param_both
.
TYPES: tty_param_both
TYPE STANDARD TABLE OF sty_param_both
.
*----------------------------------------------------------------------*
* CLASS lcl_alv DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_alv
DEFINITION.
PUBLIC SECTION.
METHODS:
constructor
IMPORTING
iv_usr1
TYPE xubname
iv_usr2
TYPE xubname
iv_tabname
TYPE tabname
it_param
TYPE tty_param_both
,
generate_alv
.
PRIVATE SECTION.
TYPES: BEGIN OF gt_t_heading
,
operand
(12) TYPE c,
valtyp
TYPE char30
,
client TYPE char10
,
system
TYPE char30
,
END OF gt_t_heading
.
DATA: v_usr1
TYPE xubname
,
v_usr2
TYPE xubname
,
v_tabname
TYPE tabname
,
t_param
TYPE tty_param_both
,
o_salv
TYPE REF TO cl_salv_table
,
o_header
TYPE REF TO cl_salv_form_layout_grid
,
o_h_label
TYPE REF TO cl_salv_form_label
,
o_h_flow
TYPE REF TO cl_salv_form_layout_flow
,
o_ex
TYPE REF TO cx_root
.
METHODS:
set_columns
,
set_header
,
set_rows_color
.
ENDCLASS. "lcl_alv DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_alv IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_alv
IMPLEMENTATION.
METHOD: constructor
.
super
->constructor
( ).
v_usr1
= iv_usr1
.
v_usr2
= iv_usr2
.
v_tabname
= iv_tabname
.
t_param
= it_param
.
ENDMETHOD. "constructor
METHOD generate_alv
.
TRY.
cl_salv_table
=>factory
(
IMPORTING
r_salv_table
= o_salv
CHANGING
t_table
= t_param
).
CATCH cx_root
INTO o_ex
.
MESSAGE o_ex
TYPE 'E'.
ENDTRY.
me
->set_header
( ).
me
->set_columns
( ).
me
->set_rows_color
( ).
o_salv
->display
( ).
ENDMETHOD. "constructor
METHOD set_columns
.
DATA: lo_columns
TYPE REF TO cl_salv_columns_table
,
lo_column
TYPE REF TO cl_salv_column_table
,
lv_title_s
TYPE scrtext_s
,
lv_title_m
TYPE scrtext_m
,
lv_title_l
TYPE scrtext_l
.
lo_columns
= o_salv
->get_columns
( ).
lo_columns
->set_optimize
( abap_true
).
TRY.
lv_title_s
= v_usr1
.
CONCATENATE v_usr1 space
'value' INTO lv_title_m RESPECTING BLANKS
.
CONCATENATE v_usr1 space
'value' INTO lv_title_l RESPECTING BLANKS
.
lo_column ?= lo_columns
->get_column
( 'PARVA1' ).
lo_column
->set_short_text
( lv_title_s
).
lo_column
->set_medium_text
( lv_title_m
).
lo_column
->set_long_text
( lv_title_l
).
CLEAR: lv_title_s
, lv_title_m
, lv_title_l
.
lv_title_s
= v_usr2
.
CONCATENATE v_usr2 space
'value' INTO lv_title_m RESPECTING BLANKS
.
CONCATENATE v_usr2 space
'value' INTO lv_title_l RESPECTING BLANKS
.
lo_column ?= lo_columns
->get_column
( 'PARVA2' ).
lo_column
->set_short_text
( lv_title_s
).
lo_column
->set_medium_text
( lv_title_m
).
lo_column
->set_long_text
( lv_title_l
).
lo_column ?= lo_columns
->get_column
( 'PARID1' ).
lo_column
->set_visible
( abap_false
).
lo_column ?= lo_columns
->get_column
( 'PARID2' ).
lo_column
->set_visible
( abap_false
).
lo_column ?= lo_columns
->get_column
( 'STATUS' ).
lo_column
->set_visible
( abap_false
).
CATCH cx_salv_not_found
. "#EC NO_HANDLER
ENDTRY.
ENDMETHOD. "set_columns
METHOD set_header
.
" Simplified RSUSR050 code for header
DATA: lo_grid
TYPE REF TO cl_salv_form_layout_grid
,
lo_label
TYPE REF TO cl_salv_form_label
, "#EC NEEDED
lo_text
TYPE REF TO cl_salv_form_text
, "#EC NEEDED
lv_row
TYPE i,
lv_column
TYPE i,
lv_title
TYPE c LENGTH
100.
CONCATENATE 'Comparison of user parameters for table ' space v_tabname
INTO lv_title RESPECTING BLANKS
.
DATA: lt_heading
TYPE STANDARD TABLE OF gt_t_heading
,
ls_heading
LIKE LINE OF lt_heading
,
lv_lsind
TYPE i.
ls_heading
-operand
= 'User'.
ls_heading
-valtyp
= 'Name'.
ls_heading
-client = 'Client'.
ls_heading
-system
= 'System'.
APPEND ls_heading
TO lt_heading
.
CLEAR ls_heading
.
ls_heading
-operand
= 'A'.
ls_heading
-valtyp
= v_usr1
.
ls_heading
-client = sy
-mandt
.
ls_heading
-system
= sy
-sysid
.
APPEND ls_heading
TO lt_heading
.
CLEAR ls_heading
.
ls_heading
-operand
= 'B'.
ls_heading
-valtyp
= v_usr2
.
ls_heading
-client = sy
-mandt
.
ls_heading
-system
= sy
-sysid
.
APPEND ls_heading
TO lt_heading
.
CLEAR: lv_row
, lv_column
.
CREATE OBJECT lo_grid
.
lo_grid
->create_header_information
(
row
= 1
column
= 1
colspan
= 20
text = lv_title
).
lo_grid
->add_row
( ).
READ TABLE lt_heading
INTO ls_heading
INDEX 1.
lv_column
= 11.
lo_label
= lo_grid
->create_label
( row
= 3
column
= 2
text = ls_heading
-operand
).
lo_label
= lo_grid
->create_label
( row
= 3
column
= 5
text = ls_heading
-valtyp
).
lv_column
= lv_column +
10.
lo_label
= lo_grid
->create_label
( row
= 3
column
= lv_column
text = ls_heading
-client ).
lv_column
= lv_column +
10.
lo_label
= lo_grid
->create_label
( row
= 3
column
= lv_column
text = ls_heading
-system
).
lv_row
= 4.
LOOP AT lt_heading
INTO ls_heading
FROM 2.
lv_column
= 11.
lo_text
= lo_grid
->create_text
( row
= lv_row
column
= 2
text = ls_heading
-operand
).
lo_text
= lo_grid
->create_text
( row
= lv_row
column
= 5
text = ls_heading
-valtyp
).
lv_column
= lv_column +
10.
lo_text
= lo_grid
->create_text
( row
= lv_row
column
= lv_column
text = ls_heading
-client ).
lv_column
= lv_column +
10.
lo_text
= lo_grid
->create_text
( row
= lv_row
column
= lv_column
text = ls_heading
-system
).
lv_row
= lv_row +
1.
ENDLOOP.
o_salv
->set_top_of_list
( lo_grid
).
ENDMETHOD. "set_header
METHOD set_rows_color
.
DATA: lo_cols_tab
TYPE REF TO cl_salv_columns_table
,
lt_s_color
TYPE lvc_t_scol
,
ls_s_color
TYPE lvc_s_scol
.
FIELD-SYMBOLS: <fs_param>
LIKE LINE OF t_param
.
LOOP AT t_param
ASSIGNING <fs_param>
.
IF ( <fs_param>
-parid1
IS INITIAL ) OR ( <fs_param>
-parid2
IS INITIAL ).
ls_s_color
-color-col
= col_negative.
ELSE.
IF ( <fs_param>
-parva1
NE <fs_param>
-parva2
).
ls_s_color
-color-col
= 3. " yellow
ELSE.
ls_s_color
-color-col
= col_positive
.
ENDIF.
ENDIF.
ls_s_color
-color-int
= 0.
ls_s_color
-color-inv
= 0.
APPEND ls_s_color
TO lt_s_color
.
CLEAR ls_s_color
.
<fs_param>
-t_color
= lt_s_color
.
CLEAR lt_s_color
.
ENDLOOP.
lo_cols_tab
= o_salv
->get_columns
( ).
TRY.
lo_cols_tab
->set_color_column
( 'T_COLOR' ).
CATCH cx_salv_data_error
.
ENDTRY.
ENDMETHOD. "set_rows_color
ENDCLASS. "lcl_alv IMPLEMENTATION
*----------------------------------------------------------------------*
* CLASS lcl_user_cmp DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_user_cmp
DEFINITION.
PUBLIC SECTION.
METHODS compare_users
IMPORTING iv_usr1
TYPE xubname
iv_usr2
TYPE xubname
iv_tabname
TYPE tabname
iv_sort_parid
TYPE abap_bool
.
CLASS-METHODS get_instance RETURNING
value(ro_obj
) TYPE REF TO lcl_user_cmp
.
CLASS-METHODS check_authorization
.
PRIVATE SECTION.
TYPES: tty_param
TYPE STANDARD TABLE OF usparam
.
CLASS-DATA: o_user_cmp
TYPE REF TO lcl_user_cmp
.
DATA: o_alv
TYPE REF TO lcl_alv
.
METHODS get_user_param
IMPORTING iv_usr
TYPE xubname
EXPORTING et_param
TYPE tty_param
.
ENDCLASS. "lcl_user_cmp DEFINITION
*----------------------------------------------------------------------*
* CLASS lcl_user_cmp IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_user_cmp
IMPLEMENTATION.
METHOD compare_users
.
DATA: lt_param1
TYPE tty_param
,
lt_param2
TYPE tty_param
,
lt_param_both
TYPE STANDARD TABLE OF sty_param_both
,
ls_param_both
LIKE LINE OF lt_param_both
.
me
->get_user_param
(
EXPORTING
iv_usr
= iv_usr1
IMPORTING
et_param
= lt_param1
).
me
->get_user_param
(
EXPORTING
iv_usr
= iv_usr2
IMPORTING
et_param
= lt_param2
).
FIELD-SYMBOLS: <fs_param>
TYPE usparam
.
" store whole first table
LOOP AT lt_param1
ASSIGNING <fs_param>
.
CLEAR ls_param_both
.
ls_param_both
-parid
= <fs_param>
-parid
.
ls_param_both
-parid1
= abap_true
.
ls_param_both
-parva1
= <fs_param>
-parva
.
ls_param_both
-partext
= <fs_param>
-partext
.
ls_param_both
-status
= 'E'. " ID does not fit by default
APPEND ls_param_both
TO lt_param_both
.
ENDLOOP.
" loop over second param table
LOOP AT lt_param2
ASSIGNING <fs_param>
.
CLEAR ls_param_both
.
READ TABLE lt_param_both
INTO ls_param_both
WITH KEY parid
= <fs_param>
-parid
.
IF sy
-subrc
EQ 0.
" The same ID already exists, alter existing row
ls_param_both
-parid2
= abap_true
.
ls_param_both
-parva2
= <fs_param>
-parva
.
IF ls_param_both
-parva1
EQ <fs_param>
-parva
.
ls_param_both
-status
= 'S'.
ELSE.
ls_param_both
-status
= 'W'.
ENDIF.
MODIFY lt_param_both
FROM ls_param_both
INDEX sy
-tabix
TRANSPORTING parid2 parva2 status
.
ELSE.
" Insert complete new row
ls_param_both
-parid
= <fs_param>
-parid
.
ls_param_both
-parid2
= abap_true
.
ls_param_both
-parva2
= <fs_param>
-parva
.
ls_param_both
-partext
= <fs_param>
-partext
.
ls_param_both
-status
= 'E'.
APPEND ls_param_both
TO lt_param_both
.
ENDIF.
ENDLOOP.
IF iv_sort_parid
EQ abap_true
.
SORT lt_param_both
BY parid
.
ELSE.
SORT lt_param_both
BY status
.
ENDIF.
FREE o_alv
.
CREATE OBJECT o_alv
EXPORTING
iv_usr1
= iv_usr1
iv_usr2
= iv_usr2
iv_tabname
= iv_tabname
it_param
= lt_param_both
.
o_alv
->generate_alv
( ).
ENDMETHOD. "compare_users
METHOD get_instance
.
IF o_user_cmp
IS NOT BOUND.
CREATE OBJECT o_user_cmp
.
ENDIF.
ro_obj
= o_user_cmp
.
ENDMETHOD. "get_instance
METHOD check_authorization
.
CLEAR: sy
-msgid
, sy
-msgty
, sy
-msgno
, sy
-msgv1
, sy
-msgv2
, sy
-msgv3
, sy
-msgv4
.
CALL FUNCTION 'AUTHORITY_CHECK_TCODE'
EXPORTING
tcode
= 'SU01D'
EXCEPTIONS
ok
= 0
not_ok
= 1
OTHERS = 2.
IF sy
-subrc <>
0.
IF sy
-msgid
IS INITIAL OR sy
-msgty
IS INITIAL.
MESSAGE i172
(00) DISPLAY
LIKE 'I' WITH sy
-tcode
.
ELSE.
MESSAGE ID sy
-msgid
TYPE sy
-msgty
NUMBER sy
-msgno
DISPLAY
LIKE sy
-msgty
WITH sy
-msgv1 sy
-msgv2 sy
-msgv3 sy
-msgv4
.
ENDIF.
LEAVE PROGRAM.
ENDIF.
ENDMETHOD. "check_authorization
METHOD get_user_param
.
CALL FUNCTION 'SUSR_USER_PARAMETERS_GET'
EXPORTING
user_name
= iv_usr
with_text
= space
TABLES
user_parameters
= et_param
EXCEPTIONS
user_name_not_exist
= 1
OTHERS = 2.
ENDMETHOD. "check_authorization
ENDCLASS. "lcl_user_cmp IMPLEMENTATION
DATA: go_user_cmp
TYPE REF TO lcl_user_cmp
,
gv_tabname
TYPE tabname
.
TABLES sscrfields
.
" Usernames
SELECTION-SCREEN BEGIN OF BLOCK bl_users
WITH FRAME TITLE tx_01
.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 1(6) tx_02
FOR FIELD p_usr1
.
PARAMETERS p_usr1
TYPE xubname
MATCHCODE OBJECT user_addr
.
SELECTION-SCREEN COMMENT 40(6) tx_03
FOR FIELD p_usr2
.
PARAMETERS p_usr2
TYPE xubname
MATCHCODE OBJECT user_addr
.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_users
.
" Table choice
SELECTION-SCREEN BEGIN OF BLOCK bl_tabs
WITH FRAME TITLE tx_08
.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_tab1
RADIOBUTTON GROUP rg1
.
SELECTION-SCREEN COMMENT 4(23) tx_04
FOR FIELD r_tab1
.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_tab2
RADIOBUTTON GROUP rg1
.
SELECTION-SCREEN COMMENT 4(23) tx_05
FOR FIELD r_tab2
.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_tabs
.
" Sort choice
SELECTION-SCREEN BEGIN OF BLOCK bl_sort
WITH FRAME TITLE tx_09
.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_sort1
RADIOBUTTON GROUP rg2
.
SELECTION-SCREEN COMMENT 4(24) tx_06
FOR FIELD r_sort1
.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_sort2
RADIOBUTTON GROUP rg2
.
SELECTION-SCREEN COMMENT 4(24) tx_07
FOR FIELD r_sort2
.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_sort
.
SELECTION-SCREEN PUSHBUTTON
1(25) tx_10
USER-COMMAND onli
.
************************************************************************
INITIALIZATION.
************************************************************************
" Authorization
lcl_user_cmp
=>check_authorization
( ).
" Get main class instance
go_user_cmp
= lcl_user_cmp
=>get_instance
( ).
" Screen buttons for SUIM comaprison programs
SELECTION-SCREEN : FUNCTION KEY 1.
SELECTION-SCREEN : FUNCTION KEY 2.
SELECTION-SCREEN : FUNCTION KEY 3.
SELECTION-SCREEN : FUNCTION KEY 4.
" Selection screen texts
tx_01
= 'Compare user parameters for:'.
tx_02
= 'User A'.
tx_03
= 'User B'.
tx_04
= 'User parameters (USR05)'.
tx_05
= 'User parameters (ZPC01)'.
tx_06
= 'Sort by PARAM id (ABC)'.
tx_07
= 'Sort by Differences'.
tx_08
= 'Choose parameter table'.
tx_09
= 'Choose sort'.
tx_10
= 'Compare user parameters'.
sscrfields
-functxt_01
= 'Compare Users'.
sscrfields
-functxt_02
= 'Roles'.
sscrfields
-functxt_03
= 'Profiles'.
sscrfields
-functxt_04
= 'Authorizations'.
************************************************************************
AT SELECTION-SCREEN.
************************************************************************
CASE sy
-ucomm
.
WHEN 'FC01'.
SUBMIT rsusr050 VIA
SELECTION-SCREEN USING SELECTION
-SET 'SAP&_BENUTZER' AND RETURN.
WHEN 'FC02'.
SUBMIT rsusr050 VIA
SELECTION-SCREEN USING SELECTION
-SET 'SAP&_ROLLE' AND RETURN.
WHEN 'FC03'.
SUBMIT rsusr050 VIA
SELECTION-SCREEN USING SELECTION
-SET 'SAP&_PROFILE' AND RETURN.
WHEN 'FC04'.
SUBMIT rsusr050 VIA
SELECTION-SCREEN USING SELECTION
-SET 'SAP&_BERECHTIG' AND RETURN.
WHEN OTHERS.
IF ( p_usr1
IS INITIAL ) OR ( p_usr2
IS INITIAL ).
MESSAGE e279
(01) DISPLAY
LIKE 'I'.
ENDIF.
ENDCASE.
************************************************************************
START-OF-SELECTION.
************************************************************************
" Run comparison for table:
CASE abap_true
.
WHEN r_tab1
.
gv_tabname
= 'USR05'.
WHEN r_tab2
.
gv_tabname
= 'ZUSER_TAB'.
ENDCASE.
go_user_cmp
->compare_users
( iv_usr1
= p_usr1
iv_usr2
= p_usr2
iv_tabname
= gv_tabname
iv_sort_parid
= r_sort1
).
END-OF-SELECTION.