Using the Utilities Process Framework for background processing
Finally, I find time to write my first blog on the new SCN platform. I’ll use this to blog about a topic that I have been thinking about for quite some time now.
In SAP CRM for Utilities the Utilities Process Framework (cf. Utilities Process Framework Cookbook) was introduced to support the implementation of complex processes like a Move-In process. The following figure shows the high level architecture of the Utilities Process Framework:
In SAP CRM 7.0 EhP 2 the Utilities Process Framework was extended by the Check Repository (cf. Business Function Energy Retailer 2 or my blog on The Utilities Check Cockpit (UCC) and the Check Repository in the process framework). Together the Utilities Process Framework and the Check Repository are quite powerful tools to extend the standard utilities processes. For example, for different customers we implemented checks in the Check Repository that
- Check certain data of the process an raise error or warning messages (e.g. check the age of the customer or check if a address is located in the service area)
- Set product configuration parameters automatically (e.g. pre-select a certain product based on a customers address).
However, the problem with the Utilities Process Framework and the Check Repository is, that they were designed to support UI processes and not background processes. In this blog I’ll show how the Utilities Process Framework can be used to implement background processes in SAP CRM for Utilities
Frontend Processes vs. Background Processes
In the utilities industry it is quite common to implement similar or even equivalent processes as frontend processes as well as background processes. Think of a simple product change process as an example. This process might be executed by a call centre agent in the SAP CRM Web UI and might as well be executed automatically in the background. The former process variant occurs if a customer calls the call centre to switch to an alternative product, the latter process might occur if the customer fills in a form which is then processed by an input management software.
Using the Utilities Process Framework and the Check Repository the standard frontend processes can easily be enhanced and extended (e.g. by additional checks like a check for a certain postal code range). However, there is no standard framework available in SAP CRM for Utilities to implement background processes. The result is that background processes are usually implemented using a mixture of different APIs like the CRM One Order function modules, certain BOL and GenIL object and some specific CRM for Utilities Classes (e,g, cl_crm_isu_order_change). All the checks implemented in the Utilities Process Framework need to be reimplemented using the APIs mentioned above. The result is that the same business logic is duplicated in at least two areas. This sooner or later leads to inconsistencies between the different implementations.
Implementing Background Processes using the Utilities Process Framework
For the following discussion I assume that a frontend process has already been implemented and tested using the Utilities Process Framework. In order to implement a background process on this basis the following steps are necessary:
- Instantiate the process manager
- Fill the process context
- Check id the process is executable and start the process manager
- Set the data on the order item level
- Finish the process manager and commit the transaction.
Instantiating the process manager
Instantiating the process manager is straight forward. Using the get_instance method and the process profile the process manager can be instantiated.
Fill the process context
DATA(proc_mgr) = cl_crm_iu_process_mgr=>get_instance( profile_id = |ZB2C| ). CHECK proc_mgr IS BOUND.
Filling the process context is a little bit more complicated as it depends on the executed process which data is required in the context. Sometimes finding the right data requires a little debugging. However, for most processes supplying the business partner as shown in the following snippet is sufficient.
DATA(proc_context) = proc_mgr->get_context( definition_id = |Z_QUOTE_CREATE| category_id = |IUQC| ). proc_context->set_container_value( name = 'PARTNER' value = i_tg_item->get_property_as_string( iv_attr_name = |PARTNER| ) ).
Note that to get the process context the process definition id as well as the category id are required. Both can be found in the customizing for the Utilities Process Framework.
Start the process manager
The next step is to start the process manager, which in turn starts the process. To do so one first needs to check if the desired process is executable. Again the definition id and the category id are required.
IF abap_true = proc_mgr->is_executable( definition_id = |Z_QUOTE_CREATE| ). proc_mgr->start( EXPORTING definition_id = |Z_QUOTE_CREATE| category_id = |IUQC| ). ... ENDIF.
Set data on item level
The next step is the most complex one. Depending on the process different data needs to be set on the item level. These are the task that a user would perform in the UI. In a move in process this could, for example, include setting the PoD, setting the product, setting product attributes, setting data required for the inter company data exchange, setting business agreement attributes and so forth. In the example below I simply create a utilities quote for a B2C product. Therefore, only the PoD and the product are required. Furthermore, I also need to convert between the different representations of a GUID used for the PoD in the BOL and in the CL_CRM_ISU_ORDER* classes. Why this is the case is beyond me…
DATA(item_guid) = proc_mgr->add_item( ). cl_system_uuid=>convert_uuid_c32_static( EXPORTING uuid = CONV #( i_i_object->get_property_as_string( iv_attr_name = |IOBJECT_GUID| ) ) IMPORTING uuid_c22 = DATA(pod_guid) ). cl_crm_isu_order_change=>set_pod( iv_guid = item_guid iv_pod_guid = pod_guid ). cl_crm_isu_order_change=>set_product( iv_guid = item_guid iv_ordered_prod = |S_GV| ).
Finishing the process and commit the transaction
The final step is to invoke the finish method of the process manager. This in turn triggers consistency checks. If there is still an error in the order, an exception is raised. In this case the underlying error messages can be read an e.g. a log entry can be written or a work item for an user can be created.
TRY. proc_mgr->finish( EXPORTING definition_id = |Z_QUOTE_CREATE| category_id = |IUQC| ). CATCH cx_crm_iu_process_exec_failed. LOOP AT proc_mgr->get_items( category_id = |IUQC| ) ASSIGNING FIELD-SYMBOL(<item>). cl_crm_isu_order_check=>message_read( EXPORTING iv_guid = <item> IMPORTING et_msg_info = DATA(msg_infos) ). ... ENDTRY.
If no error occurred the order object can be saved using the code below.
DATA(transaction) = cl_crm_bol_core=>get_instance( )->get_transaction( ). IF transaction->check_save_needed( ) = abap_true. IF transaction->check_save_possible( ) = abap_true. IF transaction->save( ) = abap_true. transaction->commit( ). ENDIF. ENDIF. ENDIF.
The advantage of the approach described above is that enables the reuse of the business logic implemented using the Utilities Process Framework and the Check Repository also in background processes. Instead of duplicating the business logic the same processes are executed in a background process as in the frontend process. Furthermore, using the Utilities Process Framework leads to much cleaner implementations of background processes as most of the complexity is provided by the implementation of the Utilities Process Framework already. Therefore, the resulting implementations are much easier to maintain.