ABAP – Number ranges usage

SAP 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.

Selection screen

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.

Result screen

Leave a Reply