Hello Folks,

I hope you are doing good.

A couple of days ago I came across a situation that is, a little bit, unusual. I was dealing with work statuses and locking on certain data regions.

In short, the scenario that I’m working on demands that a certain ENTITY owner locks several [VERSION,TIME] (VERSION is a CATEGORY dimension) combinations in one shot. Instead of letting him do this manually, I thought of using Script Logic.

I already knew that Script Logic would not contain a straightforward way to do this (I mean the NW SL has a reduced feature set from its MS counterpart, and the MS version couldn’t do this directly so…), so I thought to myself: Why don’t I use BAdI?

After a little digging inside the BW object explorer, I found the ABAP classes that manage the Work Statuses and I found a little example built-in with a sample program to test those classes right inside BW. What a jolly coincidence, thank you SAP!

I started copying and pasting the bits and pieces, modifying and shrinking the source to form just just what I needed.

I came up with the following code (Excuse my lousy coding, I met ABAP a week ago. Good thing it’s object oriented!)

method IF_UJ_CUSTOM_LOGIC~EXECUTE.

******** Data and Type declarations

    TYPES: BEGIN OF t_dims,

            dimension   TYPE uj_dim_name,   ” Dimension Name

            parameter   TYPE char20,        ” Parameter Name

            modif_id    TYPE char04,        ” Modification Group

            text_id     TYPE char20,        ” Text(Label) Field

           END OF t_dims.

    DATA: user type UJ0_S_USER,

          user_id        TYPE uj0_s_user-user_id,

          gr_work_status_mgr type ref to CL_UJW_WORK_STATUS_MGR,

          lt_dim_mem TYPE ujw_t_dim_mem,

          ls_dim_mem LIKE LINE OF lt_dim_mem,

          gt_dims TYPE TABLE OF t_dims,

          gs_dims LIKE LINE OF gt_dims,

          gs_user TYPE uj0_s_user,

          appset_id      TYPE uja_appset_info-appset_id,

          incl_child     TYPE abap_bool,

          status         TYPE uj_status,

          gr_exception       TYPE REF TO cx_uj_static_check, “cx_ujw_work_status_error,

          ls_param TYPE ujk_s_script_logic_hashentry,

          l_log TYPE string,

          l_entity(32) TYPE c,

          l_time(32) TYPE c,

          l_status(32) TYPE c,

          l_version(32) TYPE c,

          application_id TYPE uja_appl-application_id.

    FIELD-SYMBOLS: <lv_member> TYPE ANY.

******** Since this is an implementation of the BADI_UJ_CUSTOM_LOGIC interface, I used the following parameters to get the Appset and the application IDs.

    appset_id = I_APPSET_ID.

    application_id = I_APPL_ID.

******** I hardcoded my user id just for testing purposes.

******** You can use an ABAP method that can get you the currently logged-on user. In fact this is what you should do!

    user_id = ‘RIZKJ’.

    gs_user-USER_ID = user_id.

******** I do not want to include the children of the entity!

    incl_child = abap_false.

******** I started reading the parameters that will be passed from Script Logic:

    CLEAR ls_param.

    READ TABLE it_param WITH KEY hashkey = ‘VERSION’ INTO ls_param.

    IF sy-subrc NE 0.

    l_log = ‘You have not specified the parameter ”VERSION” which is required.’.

    cl_ujk_logger=>log( i_object = l_log ).

    RAISE EXCEPTION TYPE cx_uj_custom_logic.

    EXIT.

    ENDIF.

    l_version = ls_param-hashvalue.

    cl_ujk_logger=>log( i_object = l_version ).

    CLEAR ls_param.

    READ TABLE it_param WITH KEY hashkey = ‘ENTITY’ INTO ls_param.

    IF sy-subrc NE 0.

    l_log = ‘You have not specified the parameter ”ENTITY” which is required.’.

    cl_ujk_logger=>log( i_object = l_log ).

    RAISE EXCEPTION TYPE cx_uj_custom_logic.

    EXIT.

    ENDIF.

    l_entity = ls_param-hashvalue.

    cl_ujk_logger=>log( i_object = l_entity ).

    CLEAR ls_param.

    READ TABLE it_param WITH KEY hashkey = ‘TIME’ INTO ls_param.

    IF sy-subrc NE 0.

    l_log = ‘You have not specified the parameter ”TIME” which is required.’.

    cl_ujk_logger=>log( i_object = l_log ).

    RAISE EXCEPTION TYPE cx_uj_custom_logic.

    EXIT.

    ENDIF.

    l_time = ls_param-hashvalue.

    cl_ujk_logger=>log( i_object = l_time ).

    CLEAR ls_param.

    READ TABLE it_param WITH KEY hashkey = ‘STATUS’ INTO ls_param.

    IF sy-subrc NE 0.

    l_log = ‘You have not specified the parameter ”STATUS” which is required.’.

    cl_ujk_logger=>log( i_object = l_log ).

    RAISE EXCEPTION TYPE cx_uj_custom_logic.

    EXIT.

    ENDIF.

    l_status = ls_param-hashvalue.

    cl_ujk_logger=>log( i_object = l_status ).

********Here, we are reading the parameter that will contain the status. The status is a numerical code that is found in a table starting with “UJW_”. Just search for it and you will find it!

    status = l_status.

******** Here, we are filling the dimension table that will contain the dimensions intersection that will be affected by the work status change.

      CLEAR ls_dim_mem.

      ls_dim_mem-dimension = ‘MINING_ENTITY’.

      ASSIGN l_entity TO <lv_member>.

      ls_dim_mem-member = <lv_member>.

      APPEND ls_dim_mem TO lt_dim_mem.

      CLEAR ls_dim_mem.

      ls_dim_mem-dimension = ‘TIME’.

      ASSIGN l_time TO <lv_member>.

      ls_dim_mem-member = <lv_member>.

      APPEND ls_dim_mem TO lt_dim_mem.

      CLEAR ls_dim_mem.

      ls_dim_mem-dimension = ‘VERSION’.

      ASSIGN l_version TO <lv_member>.

      ls_dim_mem-member = <lv_member>.

      APPEND ls_dim_mem TO lt_dim_mem.

******** And this is where the magic happens! We instantiate the gr_work_status_mgr object with a factory object builder (nice use of design patterns!)

    gr_work_status_mgr = cl_ujw_work_status_mgr=>factory(

                               is_user   = gs_user

                               i_appset  = appset_id ).

******** And we call the method that will change the work status!

    TRY.

      gr_work_status_mgr->update_work_status_locks(

            EXPORTING

              i_applid        = application_id

              it_dim_mem      = lt_dim_mem

              i_incl_children = incl_child

              i_status        = status         ).

      MESSAGE  text-023 TYPE ‘S’.

      CATCH cx_uj_static_check INTO gr_exception.

******** I caught the exception and did absolutely nothing with it! You should not! Log it or something…

    ENDTRY.

ENDMETHOD.

You have to excuse my fascination, I’m still relatively new to ABAP and I was surprised that it had incorporated some of the features of more modern programming languages. I was expecting something hideous like COBOL! (With all my excuses to all the COBOL advocates)

There are some comments that need to be put in place:

  • First: you can observe that this method is an implementation of the BADI_UJ_CUSTOM_LOGIC Business Add-In. This is necessary so you can call the method from Script Logic.
  • Second: In order to make the code available to Script Logic, you have to create a filter for the BAdI implementation. Let’s suppose that you named the filter Z_LOCK_WS.

Now to call the code from Script Logic, you have to create a new Logic Script! Name it whatever you like and put inside the following piece of script:

*START_BADI Z_LOCK_WS

QUERY = OFF

WRITE = OFF

ENTITY = E100

TIME = 2012.01

VERSION = ACTUAL

*END_BADI

You can call this method multiple times for more than one intersection. You can even use a FOR loop and some data manager variables to call this for multiple intersections at once. In example:

*FOR %CURRENT_MONTH% = $MY_MONTHS$

*START_BADI Z_LOCK_WS

QUERY = OFF

WRITE = OFF

ENTITY = E100

TIME = %CURRENT_MONTH%

VERSION = FORECAST1

*END_BADI

*NEXT

This took me quite a bit to figure out and I hope it will be useful for some. All comments are welcome!

Have a great time,

Joseph.

To report this post you need to login first.

10 Comments

You must be Logged on to comment or reply to a post.

  1. Gersh Voldman

    Hi Joseph,

    Nice posting. Have you tried using UJW_LOCKOUT_SCHEDULE_BADI which is designed specifically for such cases instead of CUSTOM_LOGIC?

    With that BADI you can allow user locking still one combination of TIME and VERSION, but when new data is written instead of checking WS of that data you just check status of predefined intesection in the BADI. It makes lock tables smaller and hence locking works faster.

    Regards,

    Gersh

    (0) 
    1. Tomas Varga

      Hi Gersh,

      like in Joseph’s example, how can I call UJW_LOCKOUT_SCHEDULE_BADI from script logic? Do I need to create a custom implementation and set the filter?


      Many thanks, Tomas.

      (0) 
      1. Gersh Voldman

        Hi Tomas,

        This BADI is not desigend to be called from script logic. What are you going to do in it if you call if from script logic?

        It’s called every time data is submitted to the Model. For it be called from Write-Back you create an implememtation and set the filter.

        Regards,

        Gersh

        (0) 
        1. Tomas Varga

          Ok, so maybe start from the beginning.

          I want to set Work Status for multiple TIME, CATEGORY, DIM3….

          Using the standard Work Status functionality only one dimension can be the leader (here is possibility to select multiple members) for other dimension I can select only one member.

          So If I want to lock 48 months and 3 categories and other DIMs it is a nightmare.

          Then I found the article from Joseph, where he can run his custom BADI in script logic and he can set work status for multiple members at once. THAT’S my target.

          You wrote him, why have you written your own code, when you can use standard…

          So how can I achieve locking of multiple members for multiple DIMs as has Joseph achieved with his custom code with the standard code you have proposed?

          Many thanks,

          Tomas.

          (0) 
          1. Gersh Voldman

            Hi Tomas,

            First of all, you can select nodes on Time and Category when you change WS. Not sure if that solves your issue.

            If it doesn’t you can chose 1 period out of 48 and when this one comes to the BADI you do nothing – system with set a WS on it. If any of the other 47 periods come you check if that 1 selected period is locked and return same status as that period has. Same fo Categories. This way your WS table will be much smaller and work faster.

            I hope you got the idea. If you didn’t, can you please open a thread in the forum so more people can comment on it.

            Regards,

            Gersh

            (0) 
  2. Ivan Blatnik

    Hi Joseph,

    great post! We will use this on the project, because customer is not satisfied with standard interface for WS change (too many options, etc).

    Did you use this on the project? I wonder if all standard checks are considered:

    • who can change the status for the dimension (Owner / Manager)?
    • which is the next status that can be used (status1 to statu3)?

    Can usage of Badi for WS change be dangerous, i.e. can we cause some inconsistencies in system tables?

    Is there any additional documentation from your project, that can be helpful? For instance about passing parameters from Input Schedule to script which calls the Badi.

    Regards

    Ivan

    (0) 
  3. SREEJA V

    Hi Joseph,

    I have tried this code in  sample environment for a specific model. It worked perfectly fine. In that specific environment, I have only two statuses say Unlocked and Locked. So i passed the value of locked status in the code and the combination that I have given is changed from Unlocked to Locked status.

    I tried the same in another environment which have three statuses as Unlocked, Submitted and Approved. But when I pass the status value of Submitted or Approved in the code, its not updating the status of the work status. Since I am not a trained Abaper I could not find the issue. Do we have any restriction on the number of statuses since I am able to make it work on one environment and not on the other.

    Can you guys please help? Hoping to get an immediate reply since I am stuck in this which stops me to proceed further.

    Thanks,

    Sreeja

    (0) 
  4. Harsha Jalakam

    Hi Joseph,

    Its a nice post.
    Would this check whether the controls are executed for the selection region?
    Or is there any way, where we can lock data, without having to run the controls?

    Regards,

    Harsha

    (0) 

Leave a Reply