Skip to Content

One thing I have learned over the years with HCM P&F is:

“When all else fails, use an Advanced Generic Service!”

…Sounds great, eh? However, one of the biggest hurdles was first learning how in the heck to even create a working Advanced Generic Service. It seemed like it was some great guarded secret by SAP. To make matters worse, in the “early days” of HCM P&F, there were no examples to even go by…just some very confusing documentation (that still exists today! haha). Thankfully, through the help of people like SAP’s own Michael Bonrat (who headed up HCM P&F in its infancy) and fellow consultant, Derrick Banks, I was able to figure out Advanced Generic Services (AGS) and begin to use them to solve more complicated issues (for example, working around some of the early bugs in the HCM P&F framework and/or handling infotypes it could not handle correctly).

     That was long ago for me. I thought that over the years SAP would roll out more examples and information about Advanced Generic Services and the “pain” I went through would not be suffered by others who came after myself and the early HCM P&F crowd. Sadly, I was mistaken. How to implement and use AGS is still something that comes up all the time. It still is not covered well by SAP in my opinion. Therefore, I am hoping this blog will help to end that for a LOT of people….so here we go….

     First off, you should already know how and where to use regular “generic services”. They are typically used for more of our  “interactive-ness” of HCM P&F. We use them to manipulate form field values such as adding one day to a date, reading values from custom tables, handle user events in configuration, take care of any special business logic for form field validations for data coming back from the user, or anything else that can be repeated without much real harm. 

      However, when it comes to making actual backend updates (create, update, or delete) , this is where you will want (and need) to use Advanced Generic Services (AGS)…and then only when the SAP supplied services (SAP_PA, SAP_PT, or SAP_PD) do not meet your needs.

      One more major thing to know before doing updates with your AGS….from SAP:

 

CAUTION

  The SAP LUW is controlled solely by the framework. Therefore, it is not permitted to execute COMMIT WORK or ROLLBACK WORK in the FLUSH method or any other method. Similarly, you are not allowed to call external coding (function modules, classes, programs, and so on) that could possibly execute COMMIT WORK or ROLLBACK WORK.

     So how do we use them correctly for updates? It really is as simple as a three step process: 

 

  1. set an instanced “ID” attribute value in the “do operations” method of your service
  2. use the instanced “ID” value to retrieve your form scenario’s step/stage’s form container values (ie. get all the current form fields and their values) in the “flush” method of your service.
  3. code for you updates based on your form field values

       

Let us look at this in a bit more detail. I will show you two methods for doing this.

  1. using the “step GUID” (the “newer” way)
  2. using the “process reference number” (which is
    the older way we had to do this before the framework set our “step
    GUID” for us)

Using STEP GUID

There are a handful of fields that the HCM P&F framework will handle for you if you define them in your form scenario fields. One of these is STEP_OBJECT_ID. You can define it in your form fields like:

hrasr_dt_1.JPG

…defined as type ASR_GUID

hrasr_dt_2.JPG

We can look at the ONE example from SAP of a AGS on how this is used. Look at the AGS implementation, HRMSSRCF_REQUISITION_ADVANCED. If we look at the class, CL_IM_HRRCF_REQUI_REQUEST, we can see how they defined “STEP_GUID”.

/wp-content/uploads/2012/08/class_attrib_130454.jpg

This field is mapped in the process HR_MSSRCF_REQUISITION to the backend service (the AGS) as:

hrasr_dt_backend1.JPG

When the “do operations” of this service are triggered (during “check and send” for example), within the “do operations” method, we simply set the STEP_GUID attribute value:

do_operations.JPG

Then in FLUSH…. IF_HRASR00GEN_SERVICE_ADVANCED~FLUSH…we simply use this “step guid” to go re-locate our form’s data container. The SAP AGS does not show a good example of this (though it does show a good one for getting attachment data!). Therefore, here is an example of something we could do to get our form fields:

stepguid_code_1.JPG

Using PROCESS REFERENCE NUMBER

We can also do something similar simply using our “process reference number”. In our form scenario fields, this is always handled for us (ie. filled in) by the HCM P&F framework engine. We simply define this in our form fields:

hrasr_dt_1b.JPG

…defined as type ASR_REFERENCE_NUMBER

hrasr_dt_2b.JPG

In our Advanced Generic Service, much like using the “step guid”, we can define an attribute of our AGS class as:

/wp-content/uploads/2012/08/class_attrib_procnum_130460.jpg

Then in our “Do Operations”, we simply “set” this attribute’s value just like we did for “step GUID”. For example,

*** Get the New Reference Number:
*** We execute this logic so once the new reference number is set, we can pass it to the Advanced Service method FLUSH.
 
LOOP AT service_datasets INTO sd_wa WHERE fieldname = ‘REFERENCE_NUMBER’.
    w_ref_num = sd_wa-fieldvalue.
 
ENDLOOP.

  IF NOT w_ref_num IS INITIAL.
    me->att_reference_number = w_ref_num.
 
ENDIF.

Then in our FLUSH method, we would simply use this process number to locate our container to retrieve all of our current form fields. You can make this a bit easier by creating a class to read your container based on the reference number/GUID passed.

class_get_container.JPG

For example, we could use this like:

   wa_ref_num = me->att_reference_number.  “<– For Advanced Service

  ** Get the data container values for the Reference Number
 
CALL METHOD zcl_hr_process_and_forms_01=>get_form_container_data
   
EXPORTING
      in_refid           = wa_ref_num
      message_handler    = message_handler
    RECEIVING
      tbl_data_container = form_data_containers.

Then it is as easy as something like…

 

  DATA wa_begda TYPE datum.
 
CLEAR field_value.
 
READ TABLE form_data_containers WITH KEY fieldname = ‘EFFECTIVE_DATE’
       
INTO form_data_container.
 
READ TABLE form_data_container-fieldvalues
            
INTO field_value INDEX 1.
  wa_begda = field_value.

…to read actual form field values.

Our class code for getting the container correctly would look something like:

class_code_1.JPG

class_code_2.JPG

From here, you can handle your updates however you like. For example, you could handle PA infotype updates that SAP_PA might not handle well/correctly or include additional business logic that you need.

     In the “old” days of HCM P&F for PA related updates using the decoupled infotype framework, we had to duplicate a lot of code to make it happen like SAP_PA would do it. We had to handle the references to the master data “factory”, handle our containers, handle getting our structure references, and much more. For example, say we wanted to just update infotype 0035, it would look something like:

  oldcode.JPG

     Thankfully, we now have the nice little function, HR_CONTROL_INFTY_OPERATION, which handles everything for us and knows whether to use the newer decoupled way or the older “infotype operations” way of doing things. Funny enough, the comments in the function call this the “new infotype framework (NITF) ” and the “old infotype framework (OITF)”. haha

     Similarly, you could handle updates to your own custom “Z” tables or really anything else you might need here in the FLUSH method.

So that is about it. Nothing really magical or secretive to it at all. Hope this helps! As always….till next time….enjoy!

To report this post you need to login first.

18 Comments

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

  1. Paul Snyman

    Hey Chris,

    Nice post. That HR_CONTROL_INFTY_OPERATION is a great tool for PA Infotypes but I don’t think it handles OM (PD) Infotypes, any pearls of wisdom you might offer? I’m hoping there is an equivalent one I’m not aware of.

    Best,

    Paul

    (0) 
  2. Ioan Radulescu

    Hi Chris,

    This blog is exactly what I need right now – if it works đŸ™‚ . So thanks already, at least I know it’s possible.

    I’ve been trying to set the STEP_OBJECT_GUID in the fields of my scenario but it never gets filled in the SERVICE_DATASETS table – it’s there but empty. I tried different UI attributes to no avail.

    Is this still working, or should I revert to using the process number (I just hope that one is also filled out)?

    Would it not be possible to get the current step somehow while my service class is being called?

    And also: is there an official help page to reinforce this “dark art” setting of the field STEP_OBJECT_GUID?

    Thanks!

    (0) 
  3. Ioan Radulescu

    Hi everybody,

    My configuration was without a workflow (NO_WORKFLOW). At the point of sending the form there is nothing saved in the T5ASR* tables yet. Maybe that’s why there is no STEP_OBJECT_GUID value. I then added PROCESS_REFERENCE_NUMBER (also in the service fields – otherwise it would not appear in the table SERVICE_DATASETS) and I finally got a value there. Unfortunately this number means little if nothing is saved yet on the DB.

    So I looked a little around in DEBUG. SAP is actually calling the service class in CL_HRASR00_DISPATCHER method FLUSH. There we would already have the fields from the records – in the variable “flushes”.

    You can see how the service class is called here (in the same FLUSH method):

        CALL METHOD ref_to_act_mapper->flush
           EXPORTING
             no_commit       = c_no_commit
             message_handler = message_handler
           IMPORTING
             log_receipts    = act_log_receipts
             is_ok           = is_ok.

    I wonder why SAP didn’t pass the content of <FINAL_FLUSHES_WA>-SRV_VALUES_OF_FIELDS in the FLUSH method of the interface IF_HRASR00GEN_SERVICE_ADVANCED. Very annoying.

    I have decided to enhance the mentioned class and transfer the “flushes” variable content. Also I will try to send a message to SAP to pass the content of the “flushes” variable through the interface to the service class.

    @Chris: I’m still very curious about where in the documentation is mentioned this behaviour of the framework towards the passing of the process_number and the step GUID. There are a couple of notes containing some references to these special form fields but nothing really clear (so far). Or where did you hear that from?

    (0) 
    1. Alfonso VandellĂ³s

      Hi Ioan,

      I have the same problem, I need to get some field values for further operation in FLUSH method of my advanced generic service but I don’t know how to enhance CL_HRASR00_DISPATCHER class in order to pass flushes to my generic service.

      Did you get it?

      KR

      (0) 
      1. Christopher Solomon Post author

        What do you mean you need “further field values”? You have access to ALL fields/values in your Advanced Generic Service. In your FLUSH method, you can use your “reference number” that you set to then get a “handle” back to YOUR data. You can make your own class with a method to read/get the data container (there are plenty of examples of how to do this and the screenshot in my blog SHOWS the code to use) and call something like…

        ** Get the data container values for the Reference Number
         
        CALL METHOD zcl_hr_process_and_forms=>get_form_container_data
           
        EXPORTING
              in_refid           = wa_ref_num
              message_handler    = message_handler

            RECEIVING
              tbl_data_container = form_data_containers.

           

            …and then say we want the “PERNR” field….we can do something like….

            DATA wa_pernr TYPE pernr_d.
         
        CLEAR field_value.
         
        READ TABLE form_data_containers WITH KEY fieldname = ‘PERNR’
               
        INTO form_data_container.

          READ TABLE form_data_container-fieldvalues
                    
        INTO field_value INDEX 1.
          wa_pernr = field_value.

        (0) 
        1. Alfonso VandellĂ³s

          Hi,

          Yes, what you are explaining is perfect if there is a workflow template assigned to the process but my case is a process with NO_WORKFLOW, so nothing is saved into database tables to retrieve within flush methods.

          What I’ve done is to save my needed fields while DO_OPERATIONS in instance attributes of my service and when flush method get them and do some z tables updates.

          KR

          (0) 
          1. Ioan Radulescu

            Hi Alfonso & Chris,

            Indeed. I tried to do the same as you recommended Chris, but as long as no_workflow – nothing is saved in the only step to the completion of the process.

            Alfonso, implement a pre-enhancement to the flush method of CL_HRASR00_DISPATCHER and export the necessary variable to a class attribute of a customer class. For extra safety you could also export the process number to the static attribute of the customer class. Later, when you’re calling the service class, call a static method from your customer class (which is de facto a buffer) to retrieve the variable(s) in question – in this method you can check if the process number is the same (for extra safety).

            (0) 
            1. Alfonso VandellĂ³s

              Thanks a lot Iolan,

              In fact I have done similar stuff but saving only relevant fields that I want to transfer in class attributes of the class of advanced generic service, I need only 3 fields. In that way, once FLUSH method is executed I have these fields ready to deal with them.

              Anyway your solution to retrieve ALL data of the container of the form is great!

              KR

              (0) 
              1. Christopher Solomon Post author

                Did you not read the blog or look at the screenshots? That is EXACTLY what it shows….having a custom class that pulls ALL the fields of the data container that you can call in your FLUSH method. did you miss that?

                (0) 
                1. Alfonso VandellĂ³s

                  Of course I’ve read it, a lot of times in fact!

                  Did you read that we don’t have any information saved on database tables T5ASR* to get fields values when NO_WORKFLOW is set on the process?

                  I quote a previous response of mine:

                  what you are explaining is perfect if there is a workflow template assigned to the process but my case is a process with NO_WORKFLOW, so nothing is saved into database tables to retrieve within flush methods.

                  Have you tried to use your code with NO_WORKFLOW processes?

                  KR

                  (0) 
                  1. Christopher Solomon Post author

                    Sorry….I guess I should be more clear….where you said “Anyway your solution to retrieve ALL data of the container of the form is great!”….that is what I was referring too.

                    In reference to “NO_WORKFLOW”….yes, used it quite a bit (even back before most anyone knew about it, you can find it in my old “tips and tricks” blog). That fact that you are using “NO_WORKFLOW” should not change the behavior of the “flush”. Using “NO_WORKFLOW” basically is like having the “SEND_VARIATION” auto set to “save”. If you are not seeing your updates/changes, then I suspect you might have an issue in your FLUSH method that is not being caught in error handling therefore you don’t see an error nor your expected result (saved/changed data). Are any other changes being made (like via SAP_PA)?

                    (0) 
  4. Jonathan Bourne

    Hi Chris,

    Error Handling from the FLUSH method

    Great blog – thank you for taking the time to write it. Do you have any experience of the error handling in the FLUSH method? I have added an error to the MESSAGE_HANDLER and I was hoping that the message would propogate back to the calling workflow task TS17900108 in the ERROR_MESSAGES binding table. I could then forward the errors to a team to handle the manual PA30/PA40.

    However, as a result of the message handler containing a message type ‘E’ (Error) the framework is trying to set the work item to status ERROR using function module SAP_WAPI_SET_ERROR (this is called from method HANDLE_ERROR of class CL_HRASR00_PROCESS_ERROR). The function call fails due to the work item being enqueued and then a short dump occurs as a result of an ASSERT command. I’d be interested to know if you’ve been able to get error reporting from the FLUSH method to work.

    Thanks again,

    Jonathan

    (0) 
  5. Frank Haschick

    Thanks Chris,

    works like a charm!

    Just two remarks for the “STEP_GUID” part, so others don’t have to search:

    1)

    you need to assign the step_guid to the step_guid-field, not the scenario_guid field, so like this:

    CALL METHOD cl_hrasr00_process_runtime=>get_instance
           EXPORTING
    *       scenario_guid         =
             step_guid             = me->step_guid

             …


    2)

    The object type for the data_container is CL_HRASR00_DATA_CONTAINER (didn’t know that, although its somehow obvious)


    Apart from that, it works good! Just wondering why the FLUSH method is called even after i pressed send (I thought it should be called only after my approval step). Mysteries of the ASR …


    Best regards,


    Frank

    (0) 
    1. Christopher Solomon Post author

      Great to hear and thanks for clearing it up (more) for folks!

      As for your issue of when Flush happens….I would have to see your config and where you set up the “save” to happen (ie. in the process start config as “write to application database” for “send variant or in the binding of workflow). Think of it like this though in general…the standard service (SAP_PA or SAP_PD….or those rare few who actually use SAP_PT) will begin the “transaction” (ie lock)….then AGS “flush” methods get called…..then the standard services do their updates/flush…..then they “unlock” (commit transaction)….of course, assuming no errors that cause rollbacks along the way.

      (0) 
      1. Frank Haschick

        Chris, you are a genius. Of course in the process start config the setting was set to “write to application database”. Boy I debugged nearly half a day for that.

        Thank you very much! đŸ™‚

        (0) 
        1. Christopher Solomon Post author

          I don’t know if I would say “genius”…..let’s just say I may or may not have known someone who long ago spent quite a lot of time trying to figure out “what the hell is going on?!?!?” when updates were happening on form submit and at the end of workflow once workflow was added to the process (NO_WORKFLOW set before) only to notice that SEND VARIANT was set to “write immediate” after hours of staring at the debugger and stepping through code. đŸ˜‰

          (0) 

Leave a Reply