Reading time: 5 minutes<\/span><\/strong><\/p>\n <\/p>\n<\/div><\/span><\/strong><\/p>\n Flexible Workflow is a Fiori integrated solution for creation of document approval processes. Its main strength, ease of use, comes from little or zero need for programming interference. Basic scenarios can be created using configuration only. If you have a more complex situation, you can use one of the available BAdIs<\/strong><\/span> – for example the MMPUR_WORKFLOW_AGENTS_V2 BAdI, which allows for customer specific approval step agent determination logic.<\/p>\n <\/a><\/p>\n Options for approval step agent determination<\/em><\/p>\n At the first glance, the BAdI seems like a perfect solution for implementation of a complex agent determination logic. It consists of a single method called GET_APPROVERS, which is populated with basic information about the document, for which the scenario was triggered.<\/p>\n <\/a><\/p>\n GET_APPROVERS method parameters<\/em><\/p>\n More information about the BAdI and its parameters can be found in the SAP OSS note #2646400. In the same note you can also read that the information about the current step (level) is available in the BAdI from the 2008 release only and only for Purchase Requisition and Central Purchase Requisition documents.<\/p>\n To be able to correctly determine the agents for the approval step, you need to know for which level the BAdI was executed. In a static scenario, where all approval steps are triggered, you can achieve this by simply counting the previous approvers, contained in the PreviousApproverList <\/strong><\/em>parameter. However, in case of two or more non-obligatory approval steps, or an obligatory step after a non-obligatory one, the PreviousApproverList<\/strong><\/em> count will give incorrect results. Consider the example as shown in the image below:<\/p>\n <\/a><\/p>\n Comparison of two Flexible Workflow scenarios<\/em><\/p>\n Scenario B shows that the level calculated based on PreviousApproverList <\/em><\/strong>will be untrue (3 instead of 4). This may cause assignment of an incorrect agent and faulty workflow processing.<\/p>\n Fortunately, you can calculate the current approval level with the information that is available in the system during the BAdI execution.<\/p>\n This information consists of two parts:<\/p>\n <\/a><\/p>\n Flexible Workflow process flow XML<\/em> <\/a><\/p>\n Information about skipped steps in Workflow log<\/em><\/p>\n You can use PurchasingDocument<\/strong> and WorkflowScenario<\/strong> parameters to obtain the first part. Method GET_WORKFLOW_INSTANCES of class CL_SWF_FLEX_DEF_FACTORY will return a list of Flexible Workflow instances executed for the document. The last instance executed (the one with the highest WORKFLOW_ID) is what you should be looking for. You then need to parse its XML and count the steps.<\/p>\n The second part is more tricky. Theoretically, there is the standard function module SWW_WI_LOG_GET_BUFFER that you can use to read the Workflow log. However, this function removes messages of the same type that were triggered in the same second, which makes it useless in this case.<\/p>\n <\/a><\/p>\n Function to read Workflow log buffer<\/em><\/p>\n To avoid this, you can use a FIELD-SYMBOL and direct Workflow log buffer assignment, which will give you access to all messages stored in the buffer.<\/p>\n Below you can find the whole logic with the method interface:<\/p>\n <\/a><\/p>\n The parameters of the approval level calculation method<\/em><\/p>\n Even though the current approval level isn’t always necessary for agent determination, there are cases where the determination would be flawed without it. Fortunately, it is possible to calculate it with the use of the Workflow log and its processing history.<\/p>\n <\/p>\n 1. IDoc modification made easy with ABAP Object Oriented Programming<\/a><\/p>\nIntroduction<\/h3>\n
The issue of missing approval level<\/h3>\n
\n\n
\n<\/div><\/li>\n<\/ul>\n
\nWhy is the level information so important?<\/h3>\n
\nApproval level calculation<\/h3>\n
\n
\n<\/div><\/li>\n<\/ul>\n
\n
<\/span><\/p>\n\n
\n<\/div><\/span><\/li>\n<\/ul>\n
\n
\nMETHOD calculate_current_level.\r\n\u00a0\u00a0DATA:\r\n\u00a0\u00a0\u00a0\u00a0lv_xml_steps \u00a0 TYPE i,\r\n\u00a0\u00a0\u00a0\u00a0lv_log_steps \u00a0 TYPE i,\r\n\u00a0\u00a0\u00a0\u00a0lv_scenario_id TYPE swd_wfd_id,\r\n\u00a0\u00a0\u00a0\u00a0lv_object_id \u00a0 TYPE sibfboriid,\r\n\u00a0\u00a0\u00a0\u00a0ls_message \u00a0 \u00a0 TYPE swf_t100ms.\r\n\r\n\u00a0\u00a0FIELD-SYMBOLS:\r\n\u00a0\u00a0\u00a0\u00a0<lt_log_buffer> TYPE swlloghist_t.\r\n\r\n\u00a0\u00a0rv_step = 0.\r\n\r\n\u00a0\u00a0lv_object_id = iv_purchase_order.\r\n\u00a0\u00a0lv_scenario_id = iv_workflow_scenario.\r\n\r\n\u00a0\u00a0DATA(lo_wf_inst) = cl_swf_flex_def_factory=>wf_inst_handler( ).\r\n\u00a0\u00a0DATA(lt_instances) = lo_wf_inst->get_workflow_instances(\r\n\u00a0\u00a0\u00a0\u00a0EXPORTING\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0iv_scenario_id = lv_scenario_id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0iv_appl_obj_id = lv_object_id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0iv_is_draft\u00a0 \u00a0 = abap_false\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0iv_context \u00a0 \u00a0 = || ).\r\n\r\n\u00a0\u00a0SORT lt_instances BY workflow_id DESCENDING.\r\n\u00a0\u00a0READ TABLE lt_instances REFERENCE INTO DATA(ld_instance) INDEX 1.\r\n\u00a0\u00a0IF sy-subrc <> 0.\r\n\u00a0\u00a0\u00a0\u00a0RAISE EXCEPTION TYPE cx_swf_flex_ifs_exception.\r\n\u00a0\u00a0ENDIF.\r\n\r\n\u00a0\u00a0DATA(lo_ixml) = cl_ixml=>create( ).\r\n\u00a0\u00a0DATA(lo_stream_factory) = lo_ixml->create_stream_factory( ).\r\n\u00a0\u00a0DATA(lo_document) = lo_ixml->create_document( ).\r\n\r\n\u00a0\u00a0\" parse xml-data into dom\r\n\u00a0\u00a0IF lo_ixml->create_parser(\r\n\u00a0\u00a0\u00a0\u00a0document = lo_document\r\n\u00a0\u00a0\u00a0\u00a0stream_factory = lo_stream_factory\r\n\u00a0\u00a0\u00a0\u00a0istream = lo_stream_factory->create_istream_xstring( string = ld_instance->xmlresource ) )->parse( ) <> 0.\r\n\r\n\u00a0\u00a0\u00a0\u00a0RAISE EXCEPTION TYPE cx_swf_flex_ifs_exception.\r\n\u00a0\u00a0ENDIF.\r\n\r\n\u00a0\u00a0\" iterate dom and count steps\r\n\u00a0\u00a0DATA(lo_process_flows_itr) = lo_document->create_iterator( ).\r\n\u00a0\u00a0lo_process_flows_itr->set_filter( lo_document->create_filter_name_ns( name = 'processFlow' ) ).\r\n\r\n\u00a0\u00a0DATA(lo_process_flow) = lo_process_flows_itr->get_next( ).\r\n\u00a0\u00a0WHILE lo_process_flow IS BOUND.\r\n\u00a0\u00a0\u00a0\u00a0DATA(lo_activities_itr) = lo_process_flow->create_iterator( ).\r\n\u00a0\u00a0\u00a0\u00a0lo_activities_itr->set_filter( lo_document->create_filter_name_ns( name = 'activity' ) ).\r\n\r\n\u00a0\u00a0\u00a0\u00a0DATA(lo_activity) = lo_activities_itr->get_next( ).\r\n\u00a0\u00a0\u00a0\u00a0WHILE lo_activity IS BOUND.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DATA(lo_attributes) = lo_activity->get_attributes( ).\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DATA(lo_runtime_status) = lo_attributes->get_named_item_ns( name = 'runtimeStatus' ).\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DATA(lv_runtime_status) = lo_runtime_status->get_value( ).\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0CASE lv_runtime_status.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WHEN 'COMPLETED' OR 'SKIPPED'.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0lv_xml_steps = lv_xml_steps + 1.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WHEN OTHERS.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\" do nothing\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ENDCASE.\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0lo_activity = lo_activities_itr->get_next( ).\r\n\u00a0\u00a0\u00a0\u00a0ENDWHILE.\r\n\r\n\u00a0\u00a0\u00a0\u00a0lo_process_flow = lo_process_flows_itr->get_next( ).\r\n\u00a0\u00a0ENDWHILE.\r\n\r\n\u00a0\u00a0\" get message from WF log's buffer\r\n\u00a0\u00a0ASSIGN ('(SAPLSWWL)LOG_BUFFER[]') TO <lt_log_buffer>.\r\n\r\n\u00a0\u00a0\" count how many steps have been skipped\r\n\u00a0\u00a0\" because of preconditions\r\n\u00a0\u00a0LOOP AT <lt_log_buffer> TRANSPORTING NO FIELDS\r\n\u00a0\u00a0\u00a0\u00a0WHERE wi_id = ld_instance->workflow_id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AND meth_user = sy-uname\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AND workarea = 'SWF_FLEX_RUN'\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AND message = '005'.\r\n\r\n\u00a0\u00a0\u00a0\u00a0lv_log_steps = lv_log_steps + 1.\r\n\u00a0\u00a0ENDLOOP.\r\n\r\n\u00a0\u00a0rv_step = lv_xml_steps + lv_log_steps.\r\n\r\n\u00a0\u00a0\" There were &1 (&2\/&3) steps before Agent Determination BAdI\r\n\u00a0\u00a0MESSAGE s007(ym) WITH rv_step lv_xml_steps lv_log_steps INTO DATA(lv_message).\r\n\u00a0\u00a0MOVE-CORRESPONDING sy TO ls_message.\r\n\r\n\u00a0\u00a0CALL FUNCTION 'SWW_WI_LOG_WRITE_SUCCESS'\r\n\u00a0\u00a0\u00a0\u00a0EXPORTING\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0do_commit \u00a0 = abap_false\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0fb_name \u00a0 \u00a0 = 'Agent Determination BAdI'\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0wi_id \u00a0 \u00a0 \u00a0 = ld_instance->workflow_id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log_message = ls_message.\r\n\r\n\u00a0\u00a0\" add 1 for current step\r\n\u00a0\u00a0rv_step = rv_step + 1.\r\nENDMETHOD.<\/pre>\n
Summary<\/h2>\n
Read also:<\/h4>\n