Skip to Content
Technical Articles
Author's profile photo Rashmi Kumar

Create a Custom Number Range for a Document Type

This blog post describes a sample business scenario for creating custom number ranges and explains how such an extension is possible on SAP S/4HANA Cloud.

For example, the company maintains documents for a fiscal year in the format YYYYNumberRange, for example 201900001, 201900002 and so on. If such a format is not available in the system, it is possible to use the extensibility concepts of SAP S/4HANA Cloud to a generate custom number range for the different business objects.

The custom number range can be generated using a custom logic in the Custom Business Objects app. This app is available within the Extensibility Catalog of the SAP FIORI dashboard. The app has options to include a custom logic for the Before Save and After Modify events.

The extension requires two custom business objects. One to maintain the characteristics of the number range, and the other to generate the custom number range. This means that in one custom business object, you define the properties of the custom number range and in the other custom business object, you use or consume the number range that was defined in the first business object.

A generated custom numbers has of two parts: a prefix and a number, and both of these are configurable by a key user.

Note: Information provided in this blog page is as per features available on SAP S/4HANA Cloud release 1905. There might be variations to screen and field names in other release versions.

Prerequisites

You have administrative access to SAP S/4HANA Cloud and have implementation experience on the system. Coding experience is also necessary, since this extensibility solution requires implementation of a coding logic.

Authorizations

Area Business Role ID
Extensibility          .  SAP_BC_CORE_EXT     

Implementation

Use the Custom Business Object app for this implementation.

  1. Create a Custom Business Object to define the properties of the custom number range.
    • Create a business object to maintain number ranges.
    • Define fields of the custom business object. For example, the code (ID of the number range) start number, current number, prefix and suffix.
  2. Create Action to increment numbers in the custom number range.
    • Open your custom business object in an edit mode.
    • Click on the Logic tab.
    • Specify the GetNextNumber action label and identifier.
    • Publish the action.
    • Open the newly published action in the edit mode.
    • Enter a logic to increment the numbers in the number range in the draft logic section.
    • Publish your custom business object.Sample Code for the action GetNextNumber
      * Action GetNextNumber for Node ID CUSTOM_NUMBER_RANGE
      *
      * Importing Parameter : association (Navigation to Parent/Child/Associated Node Instances)
      *                       write (API for creating and updating Custom Business Object Node Instances)
      * Changing Parameter  : CUSTOM_NUMBER_RANGE (Current Node Data)
      * Exporting Parameter : message (Message with Severity S(uccess), W(arning), E(rror))
      
      custom_number_range-currentnumber = custom_number_range-currentnumber + 1.​
  3. Create a New Number Range.
    • Open your custom business object in an edit mode.
    • Add a new custom number range, with relevant field data.
  4. Implement a logic to consume custom number range in a custom business Object.
    • Create a new custom business object or use an existing custom business object.
      • Field ID is a key field and it holds the number generated in the desired number range.
      • Name field holds the name of the generated ID.
      • Features such as the Determination and Validation, UI Generation, Service Generation and System Administrative Data on the General Information tab are the other relevant information that needs to be input.
    • Publish the new custom business object.
    • Implement logic in the custom business object.
      • Declare the variables that will be used in the logic implementation. The following variables are required:
        • Local variable of type of the key of the custom number range object.
        • Local structure of type of the instance of custom number range object.
        • Local variable of length 10, type char, that is used to hold the current number.
        • Local variables of timestamp type, used for the start time, end time, target waiting time and waiting time measurement.
      • Set the values of the target duration, locked variable and start time.
      • By setting the value of the lv_locked to X, the system considers the object as locked.
      • Execute the number range generation, for example, if the value of lv_locked has not changed and the waiting time is less than 200 milliseconds.Sample code for After Modification
        * After Modify Determination for Node ID Consume_Number_Range
        *
        * Importing Parameter : association (Navigation to Parent/Child/Associated Node Instances)
        *                       write (API for creating and updating Custom Business Object Node Instances)
        * Changing Parameter  : CONSUME_NUMBER_RANGE (Current Node Data)
        
        DATA:   lv_nr_range_key     TYPE YY1_KR_CUSTOM_NUMBER_RANGE,
                ls_nr_range         TYPE YY1_CUSTOM_NUMBER_RANGE,
                lv_current_nr(10)   TYPE c,
                lv_ts_start         TYPE timestampl,
                lv_ts_end           TYPE timestampl,
                lv_ts_diff          TYPE timestampl,
                lv_ts_target        TYPE timestampl.
        
        lv_ts_target = 200.
        DATA(lv_locked) = 'X'.
        GET TIME STAMP FIELD lv_ts_start.
        
        WHILE lv_locked = 'X' AND lv_ts_diff < lv_ts_target.
            TRY.
                lv_nr_range_key = 'Number_Range'.
                DATA(lo_nr_range) = write->get_root(
        
                  business_object_id = 'YY1_CUSTOM_NUMBER_RANGE'
        
                  key                = lv_nr_range_key
        
                ).
                lv_locked = ''.
        
              CATCH cx_cbo_write_not_existing.
              CATCH cx_cbo_write_locked.
                lv_locked = 'X'.
        
            ENDTRY.
        
            IF lo_nr_range IS BOUND.
              TRY.
                lo_nr_range->get(
                  IMPORTING
                    data = ls_nr_range
                ).
                lv_locked = ''.
        
                CATCH cx_cbo_write_not_existing.
                CATCH cx_cbo_write_locked.
                lv_locked = 'X'.
              ENDTRY.
        
        
              TRY.
                lo_nr_range->execute_action(
                    EXPORTING
                        action_id = 'GetNextNumber'
                    IMPORTING
                        data      = ls_nr_range
                        messages  = DATA(lt_message)
                ).
        
                IF ls_nr_range IS NOT INITIAL.
                    lv_current_nr = ls_nr_range-curentnumber.
                    CONCATENATE ls_nr_range-prefix lv_current_nr INTO consume_number_range-id.
                ENDIF.
        
                lv_locked = ''.
        
                CATCH cx_cbo_write_locked.
                    lv_locked = 'X'.
              ENDTRY.
            ENDIF.
        
            GET TIME STAMP FIELD lv_ts_end.
            lv_ts_diff = lv_ts_end - lv_ts_start.
        ENDWHILE.

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Ramesh Kotagiri
      Ramesh Kotagiri

      Hi Rashmi,

      Followed your blog and when I executed the code nothing is returned into the ID filed (next available number). Request you to please clarify what is "Number_Range" in below code. Is it the Number Range object created in S4 system. Using the NumberRange object name that is created in S4 system, here but could not get any values in response.

      WHILE lv_locked = 'X' AND lv_ts_diff < lv_ts_target.
          TRY.
              lv_nr_range_key = 'Number_Range'.
              DATA(lo_nr_range) = write->get_root(
      
                business_object_id = 'YY1_CUSTOM_NUMBER_RANGE'
      
                key                = lv_nr_range_key
      
              ).