I wanted to have a tool for monitoring usage of internal number ranges in a system (such tool should be used also as a backround job) which can alert a system administrator in case a number range is reaching end of its interval.
It should be possible to explicitly list number ranges we are interested in (parameter s_object)
I wanted to be able to set a threshold of usage in % dynamically (on selection screen) so I set it as an input parameter too (p_trshld);.
It should also be possible to exclude some range when we are simply not interested in it or it’s an “auto-rotating” number range (parameter s_excl)
So the selection screen might look like the following:
DATA:
gv_nrobj TYPE nrobj,
gv_exluded(18) TYPE c.
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME.
SELECT-OPTIONS:
s_object FOR gv_nrobj,
s_excl FOR gv_exluded NO INTERVALS.
PARAMETERS: p_trshld TYPE p DECIMALS 2 OBLIGATORY DEFAULT '90.00'.
********************************************
*** HINTS FOR THE EXCLUDED NUMBER RANGES ***
********************************************
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 1(75) s_hint.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 7(67) s_hint01.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 17(58) s_hint02.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 23(52) s_hint03.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK b01 WITH FRAME.
The output will be displayed on a screen 0100 where I created a PF_STATUS with the most common functions BACK, LEAVE and CANCEL.
Events PBO and PAI of screen 0100 are handled in a local helper class
INITIALIZATION.
%_s_object_%_app_%-text = 'Number range object'.
%_p_trshld_%_app_%-text = 'Number range usage in %'.
%_s_excl_%_app_%-text = 'Exclude number range'.
s_hint = 'Excluded Object: XXXXXXXXXXYYYYYYZZ'.
s_hint01 = 'X = Number Range'.
s_hint02 = 'Y = Sub Object'.
s_hint03 = 'Z = No.'.
START-OF-SELECTION.
lcl_app=>get_instance( )->execute( ).
MODULE pbo_0100 OUTPUT.
lcl_app=>get_instance( )->pbo_0100( ).
ENDMODULE.
MODULE pai_0100 INPUT.
CASE sy-ucomm.
WHEN 'BACK' OR 'LEAVE' OR 'CANCEL'.
LEAVE TO SCREEN 0.
ENDCASE.
ENDMODULE.
Here follows the contents of the helper class where the most important is the GET_DATA method where the relevant data is selected (and filtered)
CLASS lcl_app DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
get_instance RETURNING VALUE(ro_instance) TYPE REF TO lcl_app.
METHODS:
execute,
pbo_0100.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_s_data,
object TYPE nriv-object,
subobject TYPE nriv-subobject,
nrrangenr TYPE nriv-nrrangenr,
toyear TYPE nriv-toyear,
fromnumber TYPE nriv-fromnumber,
tonumber TYPE nriv-tonumber,
nrlevel TYPE nriv-nrlevel,
txtshort TYPE tnrot-txtshort,
usage(6) TYPE c,
END OF ty_s_data,
ty_t_data TYPE TABLE OF ty_s_data WITH DEFAULT KEY.
CLASS-DATA:
mo_instance TYPE REF TO lcl_app.
DATA:
mt_data TYPE ty_t_data,
mv_num_checked_ranges TYPE i,
mo_container TYPE REF TO cl_gui_docking_container,
mo_grid TYPE REF TO cl_gui_alv_grid.
METHODS:
get_data
RETURNING VALUE(rt_data) TYPE ty_t_data,
get_fcat_4_itab
IMPORTING it_table TYPE ANY TABLE
RETURNING VALUE(rt_fcat) TYPE lvc_t_fcat,
display_alv.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD get_instance.
IF mo_instance IS INITIAL.
CREATE OBJECT mo_instance.
ENDIF.
ro_instance = mo_instance.
ENDMETHOD.
METHOD execute.
me->mt_data = me->get_data( ).
IF me->mv_num_checked_ranges = 0.
MESSAGE 'No interval shortage detected' TYPE 'S'.
LEAVE LIST-PROCESSING.
ENDIF.
CALL SCREEN 0100.
ENDMETHOD.
METHOD pbo_0100.
DATA:
lv_msg TYPE string.
SET PF-STATUS 'PFSTATUS'.
SET TITLEBAR 'TITLEBAR'.
me->display_alv( ).
lv_msg = | Checked number ranges: { me->mv_num_checked_ranges }|.
MESSAGE lv_msg TYPE 'S'.
ENDMETHOD.
METHOD get_data.
SELECT r~object
r~subobject
r~nrrangenr
r~toyear
r~fromnumber
r~tonumber
r~nrlevel
t~txtshort
INTO CORRESPONDING FIELDS OF TABLE rt_data
FROM nriv AS r
LEFT JOIN tnrot AS t ON t~object = r~object
AND t~langu = sy-langu
WHERE r~object IN s_object
AND r~externind EQ ' '.
**********************************************************************
* FILTER DATA
* Remove excluded number ranges (given on selection screen
LOOP AT s_excl ASSIGNING FIELD-SYMBOL(<ls_excl>).
READ TABLE rt_data TRANSPORTING NO FIELDS
WITH KEY object = <ls_excl>-low+0(10)
subobject = <ls_excl>-low+10(6)
nrrangenr = <ls_excl>-low+16(2).
IF sy-subrc = 0.
DELETE rt_data INDEX sy-tabix.
ENDIF.
ENDLOOP.
* Remove entries where TOYEAR is not initial
* and not equal to current year
DELETE rt_data
WHERE toyear IS NOT INITIAL
AND toyear <> sy-datum(4).
* Remove entries where NRLEVEL is INITIAL (number range not used yet)
DELETE rt_data WHERE nrlevel IS INITIAL.
me->mv_num_checked_ranges = lines( rt_data ).
* Compute usage in %
LOOP AT rt_data ASSIGNING FIELD-SYMBOL(<ls_data>).
<ls_data>-usage = ( <ls_data>-nrlevel - <ls_data>-fromnumber ) /
( <ls_data>-tonumber - <ls_data>-fromnumber ) *
100.
ENDLOOP.
* Remove entries where usage is less than given treshold
DELETE rt_data WHERE used < p_trshld.
* Sort data by range number name
SORT rt_data BY object.
ENDMETHOD.
METHOD display_alv.
IF me->mo_grid IS INITIAL.
CREATE OBJECT mo_container
EXPORTING
parent = cl_gui_container=>screen0
repid = sy-repid
dynnr = '0100'
side = cl_gui_docking_container=>dock_at_left
extension = 10000
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5
OTHERS = 6.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
CREATE OBJECT mo_grid
EXPORTING
i_parent = me->mo_container
EXCEPTIONS
error_cntl_create = 1
error_cntl_init = 2
error_cntl_link = 3
error_dp_create = 4
OTHERS = 5.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
DATA(lt_fcat) = me->get_fcat_4_itab( me->mt_data ).
lt_fcat[ fieldname = 'USAGE' ]-scrtext_s = '%'.
lt_fcat[ fieldname = 'USAGE' ]-scrtext_m = 'Used %'.
mo_grid->set_table_for_first_display(
EXPORTING
i_save = 'A'
i_default = 'X'
CHANGING
it_outtab = me->mt_data
it_fieldcatalog = lt_fcat
EXCEPTIONS
invalid_parameter_combination = 1
program_error = 2
too_many_lines = 3
OTHERS = 4
).
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ELSE.
me->mo_grid->refresh_table_display( ).
ENDIF.
ENDMETHOD.
METHOD get_fcat_4_itab.
DATA:
lo_columns TYPE REF TO cl_salv_columns_table,
lo_aggregations TYPE REF TO cl_salv_aggregations,
lo_salv_table TYPE REF TO cl_salv_table,
lr_table TYPE REF TO data.
FIELD-SYMBOLS:
<table> TYPE STANDARD TABLE.
* Create unprotected table from import data
CREATE DATA lr_table LIKE it_table.
ASSIGN lr_table->* TO <table>.
* New ALV Instance
TRY.
cl_salv_table=>factory(
EXPORTING list_display = abap_false
IMPORTING r_salv_table = lo_salv_table
CHANGING t_table = <table>
).
CATCH cx_salv_msg. "#EC NO_HANDLER
ENDTRY.
lo_columns = lo_salv_table->get_columns( ).
lo_aggregations = lo_salv_table->get_aggregations( ).
rt_fcat = cl_salv_controller_metadata=>get_lvc_fieldcatalog(
r_columns = lo_columns
r_aggregations = lo_aggregations
).
ENDMETHOD.
ENDCLASS.