BVG India Limited deploys AWS for Disaster Recovery

BVG India Limited deploys AWS for Disaster Recovery

BVG India Limited, founded in 1997 by Mr. Hanmantrao Gaikwad, is a responsible and forward-thinking company that seeks to support India’s entire development. By 2030, the BVG group hopes to make a positive difference in the lives of ten million people through empowerment, employment, and education.

Trying to Meet Recovery Goals

BVG’s Disaster Recovery(DR) system was on the verge of failure. For disaster recovery, they used on-site infrastructure servers, which lacked the flexibility they would have needed. As a result, they lost all of their data. To overhaul its DR solution and fulfil the company’s larger goal of migration to the cloud, BVG turned to AeonX. 

BVG’s focus on customer service has fuelled a rapid level of growth since its launch around three decades ago. BVG’s DR testing and drills revealed the following issues with its existing infrastructure:

  • The solution, which was hosted on a physical server on-site, was unable to keep up with the expansion of the business. 
  • Backup was performed in the on-premise data centre, which was expensive and hard to scale as requirements increased.
  • Hardware was starting to deteriorate and would last for 2 to 3 years at most.
  • Having no disaster recovery system enabled a heavy reliance on local backups that are unreliable, which led to the loss of data.

Furthermore, it had limited assistance for technology testing and development and its systems were not as adaptable as they would have desired. Additionally, the company lacked a comprehensive business continuity and disaster recovery(DR) plan and required a technology infrastructure that could meet demand while also fostering additional expansion.

In search of reliability and automation

BVG India Limited began working with AeonX, an AWS Advanced Tier Services Partner, in the summer of 2022 to deploy AWS On-Cloud Disaster Recovery, which minimizes downtime and data loss with the quick, dependable recovery of cloud-based applications using economical storage, minimum computing, and point-in-time recovery. 

By working through the night through its 24/7 delivery centre, AeonX came up with a solution to fix the production server. It was accomplished by proposing the following structural changes:

  • By hosting Disaster Recovery on the cloud, we minimize downtime and data loss, utilizing affordable storage, minimal computing, and point-in-time recovery methods of cloud-based applications.
  • Review of monthly costs using AWS Trusted Advisor and, if necessary, recommendations to reduce the number of instances.
  • Recommended to turn off the preload option when setting up replication between primary and secondary instances. By deactivating this option, duplicated data is not loaded into the memory of the secondary HANA instance, so the second instance does not require the same amount of memory. Lowering costs while ensuring fail-safe protection.
  • By using scripting, we were able to automate the DR monitoring and DR health status.
  • With the scripting automation technique, BVG is given real-time notifications; this allows them to be informed of any problems immediately and take swift action.

With a more efficient DR solution in place, BVG India Limited has been working alongside AeonX to accelerate the migration from its on-premises data centre to the cloud on AWS. Using AWS disaster recovery hosting in the cloud, BVG has saved at least 20x on upfront costs. It improved its recovery goals, achieving an RTO of 4 hours as opposed to 12 hours (a 67 per cent jump) and an RPO of 2 hours as opposed to 4 hours (a 50 per cent boost).

Additionally, it postponed a sizable planned capital expenditure to upgrade the hardware in its DR data centre and instead redirected that money to cover the operational costs of maintaining DR in the cloud.

Public Sector Competency in AWS

Public Sector Competency in AWS

Public Sector Competency in AWS Government organizations is rapidly adopting cloud services to drive efficiency and unlock new digital experiences for their users.

As the market leader in cloud infrastructure services, Amazon Web Services (AWS) continues to see strong adoption among government agencies – particularly departments with high IT security standards and compliance requirements. 

In this brief, you will learn about the benefits of implementing AWS in government agencies. By understanding these best practices, you can ensure that your implementation of AWS will be secure and compliant with all relevant regulations. 

Read on to understand why your organization should adopt AWS, the different ways it can be implemented within your agency, and more.

Strengthening public sector infrastructure with AWS

Maintain security and compliance:

Designed with comprehensive security capabilities, AWS can meet the most rigorous requirements in terms of information security.

With AWS, you can access cloud services at every level of classification: Unclassified, Sensitive, Secret, or Top Secret.

AWS Cloud provides comprehensive controls, auditing, and wide security accreditation to support compliance with numerous laws, including those related to health, family education rights, privacy rights, and criminal justice information systems.

Drive innovation in support of citizens :

The government is better able to innovate in order to safeguard and assist individuals thanks to our builder’s mentality. More services are provided from AWS than from any other cloud provider, with 200 fully featured services available for a variety of technologies. Within such services, AWS also offers the most sophisticated capabilities.

AWS offers the most comprehensive and in-depth selection of artificial intelligence (AI) and machine learning (ML) services for your company. We are primarily concerned with resolving some of the most difficult problems that prevent every developer from using ML.

Power, modernize, and maximize enterprise systems:

The massive enterprise-level systems that manage the social, medical, and financial benefits in providing care to millions of people can be powered and transformed by AWS.

  • Get assistance with database migration and dependable, scalable data storage
  • Transform your data into valuable insights by sharing it across platforms
  • Reduce costs by quickly scaling up or down IT resources
  • The most complex organizations can easily implement sophisticated and secure access permissions and processes

Facilitate innovation and enhance the customer experience:

Access constituent services more easily and effectively for improved social outcomes.

  • Increase staff efficiency by creating mobile applications, virtual assistance, and self-service portals
  • Get instant access to powerful IT resources, like natural language processing or machine learning, to improve customer service

Make your solutions faster, better, and more accessible with AWS:

AWS unlocks business enablement, marketing, and technical resources. Connect with your customers while accelerating your go-to-market efforts.

  • Utilize technical resources, consultations, and well-architected evaluations to speed up development with AWS.
  • Create useful data visualizations to aid in decision-making

Maintain and modernize legacy databases and systems:

The scalability, high availability, and lower costs of the AWS Cloud give law enforcement and public safety organizations greater leverage.

  • Support for database migration and reliable and secure data storage
  • Ensure fast, reliable disaster recovery to minimize data loss and downtime
  • Create sophisticated and secure access permissions for organizations of any size
  • Hybrid cloud solutions using on-premises resources

How AeonX can help?

Keeping a long-term consumer focus, being hyper-vigilant, and avoiding practices that slow down innovation is essential for a company in today’s world.

The AWS Public Sector Competency demonstrates AWS technical expertise and proven customer success across a wide range of industries, use cases, and workloads. 

AeonX assists you in using the cloud to transform ideas into opportunities, resulting in new avenues for expansion, improved productivity, and improved customer service. 

With the support of our knowledgeable personnel, you may increase your company’s performance by more than 40% and get better outcomes.

Sales Order – Level Approval Workflow and release from Credit Block 2 in 1

Sales Order – Level Approval Workflow and release from Credit Block 2 in 1

There are many standard workflow scenarios available but some business requirements can not be satisfied by standard workflows. So it is important to develop something from scratch as per the business requirements. This blog post is mainly focused on the Sales Order Approval Process. In most of the case, there is only one Manager/Approver who is going to approve the SO. This can be managed by the SD Functional by some configuration and with the same configuration, you can also manage multi-level Manager/Approver too. But what if the business requirement is as bellow,

  • While creating or changing SO, a workflow should be triggered to a Manager/Approver.
  • There are 4 Level of Manager/Approver who is going to approve SO one by one.
  • Sales Order is considered to be approved if the Final Approver level has approved it.
    • Final Approver can be Level 1 , Level 2 , Level 3 or Level 4 based on the SO amount fit to the range provided to each level.
    • i.e. Level 1 ( 0 to 1,000 )
    • i.e. Level 2 ( 1,000 to 10,000 )
    • i.e. Level 3 ( 10,000 to 1,00,000 )
    • i.e. Level 4 ( 1,00,000 and above )
    • Now if SO amount is 65,000, Level 3 is the Final Approver.
  • If Sales Order is in Credit Block, workflow should be triggered to a Manager/Approver to release it from Credit Block.

Read more:- A Sap Consultant Guide 2022 : Career, Salary, Jobs, Scope, Skills

Before starting step by step implementation, let us see the basic prerequisites.

Custom Table: In SE11 -> ZSO_APPROVAL( Screenshot – 1 )

Table Maintenance : ZSO_APPROVAL. I have changed the screen, Utility->Table Maintenance Generator->Environment->Modification->Maintenance Screen.

( Screenshot – 2 )

Here, it is not necessary to maintain 4 entries. If there is only one entry like MinValue = 1.00 and Max_Value BLANK(Means anything) then Level 1 will be the Final Approver. In case there is no entry found in this custom table for a particular sales order so the sales order will be skipped from this Level-Approval Process and treated as per SAP Standard flow.

There is no Level-Approver to manage Credit Block. Only one approver is going to release sales orders from Credit Block based on the sales order amount.

Class: Create a Class in SE24, ZSO_APPROVAL_EXIT with event ‘TRIGGER‘. This class also has some interfaces, methods, and attributes that will be covered after this workflow creation steps.

( Screenshot – 3 )

Function Module: Create a Function Module in SE37 as below. There is no importing or exporting or changing parameters.

( Screenshot – 4 )

Implementation Steps:

Step 1: Create workflow and register Events + Binding.

Goto SWDD and create a new workflow. After ‘Abbreviations’ and ‘Description’ in the ‘Basic Data’ tab, you can register events in the ‘Start Event’ tab. Here, we have two events of standard BO “BUS2032” and one custom event of class “ZSO_APPROVAL_EXIT“.

( Screenshot – 5 )

Create following workflow container elements before binding them to the events.

  • Workflow Container.
    • ITAB stores HTML Content
    • ISO  stores VBELN
    • IUSER stores userid while workflow triggered for Credit Release.(VKM1)
    • BUS2032 is BO which will be used for Credit Release.(VKM1)

( Screenshot – 6 )

Binding will be the same for “CREATED” and “CHANGED” events. The required container element will receive some value whenever a sales order is created or changed.

( Screenshot – 7 )

Binding for “TRIGGER” event of class ZSO_APPROVAL_EXIT. This event will be triggered manually if SO is in Credit Block in FORM USEREXIT_SAVE_DOCUMENT of MV45AFZZ UserExit or from some BADI.

( Screenshot – 8 )

  • Note :  &EVENT_NAME& will be used to identify the triggered workflow, i.g. workflow is triggered by VA01(Created) or VA02(Changed) or VKM1(Trigger).

Step 2: Common task that will generate SO Details with List of Materials in HTML format.

Below is a sample output of this task that generates HTML content filled with required Sales Order details including a list of materials.

( Screenshot – 9 )

Create an activity with a custom task. ( Screenshot – 10 )

Fill the required field and select Object Category “ABAP Class” and in Object Type “ZSO_APPROVAL_EXIT” with Method “MATERIALS”. So each time this method gets called whenever any of the workflows is triggered. Don’t forget to make this task “BACKGROUND PROCESSING”.

( Screenshot – 11 )

In the Container tab declare ITAB with typed ZSOLISTI1_TT( which is Table Type of SOLISTI1 ). So whole HTML content will be stored in this Container Element and this ITAB is going to be placed in UserDecision Task for both workflows.

( Screenshot – 12 )

It is declared with TableType so Multiline is by default checked but in Parameter Settings check the Export checkbox. Because we are receiving HTML in it.

( Screenshot – 13 )

The Binding for this Task is simple. Just you have to pass &ISO& to MATERIALS method and it will return &ITAB&. ( ISO is Sales Order number )

( Screenshot – 14 )

Step 3: Condition to identify workflow. (Condition 000008)

Create a condition step to identify which workflow should trigger. If event_name is “CREATED” or “CHANGED” it will trigger Sales Order Approval workflow and if event_name is “TRIGGER” it will trigger a workflow to release Sales Order from Credit Block.

( Screenshot – 15 )

Step 4: Let us assume EVENT_NAME is ‘CREATED’ or ‘CHANGED’.  That means workflow triggered from VA01 or VA02. ( User Decision 000041 )

Create User Decision step with “Approve” and “Reject” buttons. Pass &ISO& in parameter 1 so it can be used in Title ” Approval for Sales Order: &1″ . &1 is our Sales Order Number. Here agent assignment is dynamic. You can skip this part for now.

( Screenshot – 16 )

In the Control tab, create a new task, and do not forget to make “General Task” in Task Properties.

( Screenshot – 17 )

Assign ZSO_APPROVAL_EXIT in the Program Exits tab. So after taking a decision, it will call that class, and here we can perform operations based on the decision.

( Screenshot – 18 )

Double click on Task “TS90000046” in the control tab. Fill all fields as below.

( Screenshot – 19 )

In the container tab, create an element with “MLIST” with the same type as we created “ITAB”. Here the lines of ITAB will be stored in “MLIST”.

( Screenshot – 20 )

Now simply declare “&MLIST[]&” in the Description tab. The whole HTML content will be displayed in User Decision BODY.

( Screenshot – 21 )

Binding for Task “TS90000046”, assign ITAB to MLIST. ( Screenshot – 22)

Goto decision tab, create a new rule and double click it. Fill the required field and in Rule Definition select “Agent Determination: Function to be Executed” and Function Module “ZRULE_FM“. (Need to create ZRULE_FM first before activating this agent assignment). Do not forget to check “Terminate If Rule Resolution Without Result.

So if there is no agent received for a particular SO, it will not trigger/dump workflow.

( Screenshot – 23 )

In the container of this Rule, create an element with the type VBELN and make it Import. ( Screenshot – 24)

Binding is again simple for this, just pass ISO. ( ISO is sales order number ) ( Screenshot – 25 )

As we did binding above for the Rule, there is an element ISO passed to SO_N. This SO_N will be received in ZRULE_FM  in wa_container-value. Based on that VBELN we can get agent from our Custom Table. Append that user-id retrieved from ZSO_APPROVAL to actor_tab.

( Code – 1 )

DATA : wa_actor     TYPE swhactor,
       wa_container TYPE swcont.
DATA : lv_lines TYPE i.

  READ TABLE ac_container INTO wa_container.
  IF wa_container-value IS NOT INITIAL.

*** Sales Order Number(VBELN) will be received in [wa_container-value]
*** Based on that you can find Sales Order Amount and than pass it to ZSO_APPROVAL table
*** So you will get list of approvers.

      wa_actor-otype = 'US'.
      wa_actor-objid = wa_soapp-userid.
      APPEND wa_actor TO actor_tab.

  ENDIF.

  DELETE ADJACENT DUPLICATES FROM actor_tab COMPARING objid.
  DESCRIBE TABLE actor_tab LINES lv_lines.
  IF lv_lines EQ 0.
    RAISE nobody_found.
  ENDIF.

Step 5: Finally, Sales Order Approval acknowledgment will be sent to the workflow initiator.

This email will be received by a workflow initiator with decisions taken by the approver and sales order details.

( Screenshot – 26 )

Create Send Mail step to send mail to the initiator. Here BUS2032 container element have enough data regarding particular Sales Order. So you can use it as bellow.

( Screenshot – 27 )

Step 6: Let us assume EVENT_NAME is ‘TRIGGER’. This workflow trigger when SO is in Credit Block. So associated approver can release it without going into VKM1.

Create Activity and create a task to Instantiate BUS2032 BO by using the sales order number. This step is necessary because to get the complete details of a particular SO.

( Screenshot – 28 )

Double-click on task. Fill the required field and do not forget to check Background Processing.

( Screenshot – 29 )

When you perform the above step, it will auto-generate Object Key, Object type, and Object instance.

( Screenshot – 30 )

Pass ISO to Objectkey and BUS2032 ( as it is – string) to the Object type. So it will instantiate BO implicitly and return it to &BUS2032& Container Element.

( Screenshot – 31 )

Step 7: User Decision for Credit Release.

Create User Decision with “Release” and “Block” buttons and pass Parameter1 with &ISO&. When we trigger the event manually from UserExit by calling ZSO_APPROVAL_EXIT-SET_PARAM method with &ISO& and &IUSER&.

( Screenshot – 32 )

Create a new task “TS****”  and do not forget to make “General Task” in Task Properties.

( Screenshot – 33 )

Assign ZSO_APPROVAL_EXIT in the Program Exits tab. So after taking a decision, it will call that class, and here we can perform operations based on the decision.

( Screenshot – 34 )

Binding is simple, pass &ITAB& to &MLIST& so HTML content can be displayed on Decision Body. Avoid Extended and Decision_note, I forgot to remove these auto-generated entries.

( Screenshot – 35 )

Step 8: Sales Order Credit Block Acknowledgement sent to the workflow initiator.

Create Send Mail step to send mail to the initiator. Here BUS2032 container element have enough data regarding particular Sales Order. So you can use it as bellow.

( Screenshot – 36 )

Reference Code.

Class ZSO_APPROVAL_EXIT – Interfaces, following interfaces must be implemented.

( Screenshot – 37 )

Class ZSO_APPROVAL_EXIT – Methods, there are only 3 methods used in this blog.

  1. IF_SWF_IFS_WORKITEM_EXIT~EVENT_RAISED
    • This method is used to handle Decision Taken by the Approver.
  2. SET_PARAMS
    • This method is used to trigger event when so is in Credit Block.
  3. MATERIALS.
    • This method is used to get Sales Order details and List of materials.

( Screenshot – 38 )

Event_Raised – Method ( Code – 2 )

IF im_event_name EQ 'AFT_EXEC'.
      CHECK ls_wihead-wi_stat NE swfco_wi_status_error
      AND   ls_wihead-wi_stat NE swfco_wi_status_excpcaught
      AND   ls_wihead-wi_stat NE swfco_wi_status_excphandlr.

      l_wf_cont = im_workitem_context->get_wf_container( ).
      l_wi_cont = im_workitem_context->get_wi_container( ).

      CALL METHOD l_wf_cont->get
        EXPORTING
          name  = 'EVENT_NAME'
        IMPORTING
          value = _wf.

      CALL METHOD l_wi_cont->get
        EXPORTING
          name  = '_WI_RESULT'
        IMPORTING
          value = _res.

***IF A Persion has clicked on Approve button, _res = 0001. and _wf will be received from Workflow.
      IF _res EQ '0001' AND ( _wf EQ 'CREATED' OR _wf EQ 'CHANGED' ).

***Code to change SO status in JEST standard table.
***You can use 'I_CHANGE_STATUS' FM
***After getting approved by the approver, it will trigger workflow to next approver level as maitained in ZSO_APPROVAL Table.
***Manually Trigger workflow to next level approver.
***
***
                  WAIT UP TO 1 SECONDS.
                  CALL FUNCTION 'SAP_WAPI_CREATE_EVENT'
                    EXPORTING
                      object_type = object_type    "BUS2032
                      object_key  = object_key     "SALES ORDER NUMBER
                      event       = event.          "CHANGED


***
***
         ELSEIF _res EQ '0001' AND _wf EQ 'TRIGGER'.

              CALL METHOD l_wf_cont->get
                 EXPORTING
                     name  = 'ISO'
                 IMPORTING
                     value = so_n.


              CALL FUNCTION 'SD_ORDER_CREDIT_RELEASE'
                 EXPORTING
                   vbeln = so_n.

***
ENDIF.

Materials – Method – to generate HTML Content. ( Code – 3 )

*** ITAB and ISO are imporing parameters.
*** By using ISO that is SO Number you can get details of Materials
*** Append each HTML Line to ITAB [ ITAB TYPE ZSOLISTI1_TT ] Create TableType of SOLISTI1.
DATA : wa_contents TYPE solisti1.

    wa_contents-line = |<html><head><style>|.APPEND wa_contents TO itab.
    wa_contents-line = '.t1 {font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;border-collapse: collapse;width: 80%;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t1 td, .t1 th {border: 1px solid #000;padding: 2px;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2{font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;border-collapse: collapse;width: 100%;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2 td, .t2 th {border: 1px solid #504F4F;padding: 5px;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2 tbody tr:nth-child(even){background-color: #f2f2f2;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2 tbody tr:hover {background-color: #ddd;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2h1 {padding-top: 12px;padding-bottom: 12px;text-align: left;background-color: #9BC2E6;color: #504F4F;}'.APPEND wa_contents TO itab.
    wa_contents-line = '.t2h2 {padding-top: 12px;padding-bottom: 12px;text-align: left;background-color: #A6A6A6;color: #504F4F;text-align:center;}'.APPEND wa_contents TO itab.
    wa_contents-line = |</style></head><body>|.APPEND wa_contents TO itab.
    wa_contents-line = |<table border="1" class="t1"><tbody>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Person Responsible</td><td>{ ename }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Sales Organization</td><td>{ wtab-vkorg }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Distribution Channel</td><td>{ wtab-vtweg }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Division</td><td>{ wtab-spart }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Sold to Party</td><td>{ wtab-name1 }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><td>Inco-Terms</td><td>{ wtab-inco1 }</td></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |</tbody></table><table border="1" class="t2" style="margin-top:10px;"><tbody>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><th class="t2h1">List of Material:</th></tr>|.APPEND wa_contents TO itab.
    wa_contents-line = |<tr><th class="t2h2">Material No</th><th class="t2h2">Material Description</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">Order Quantity</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">UOM</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">Pending Quantity</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">Basic Price</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">Amount</th>|.APPEND wa_contents TO itab.
    wa_contents-line = |<th class="t2h2">Currency</th></tr>|.APPEND wa_contents TO itab.

LOOP AT imat INTO wmat.

***GET MATERIALS DETAILS***

ENDLOOP.
wa_contents-line = |</tfoot></table></body></html>|.APPEND wa_contents TO itab.

SET_PARAMS – Method. ( Code – 4 )

 METHOD set_params.

    DATA: lv_objtype          TYPE sibftypeid,
          lv_event            TYPE sibfevent,
          lv_objkey           TYPE sibfinstid,
          lr_event_parameters TYPE REF TO if_swf_ifs_parameter_container,
          lv_param_name       TYPE swfdname,
          lv_id               TYPE char10.

    DATA : wa TYPE zmatlist.

    lv_objtype = 'ZSO_APPROVAL_EXIT'. " your class name
    lv_event   = 'TRIGGER'.  " event name.

    CALL METHOD cl_swf_evt_event=>get_event_container
      EXPORTING
        im_objcateg  = cl_swf_evt_event=>mc_objcateg_cl
        im_objtype   = lv_objtype
        im_event     = lv_event
      RECEIVING
        re_reference = lr_event_parameters.

    lv_param_name  = 'ISO'.  " parameter name of the event
    lv_id          = iso.

    TRY.
        CALL METHOD lr_event_parameters->set
          EXPORTING
            name  = lv_param_name
            value = lv_id.

      CATCH cx_swf_cnt_cont_access_denied .
      CATCH cx_swf_cnt_elem_access_denied .
      CATCH cx_swf_cnt_elem_not_found .
      CATCH cx_swf_cnt_elem_type_conflict .
      CATCH cx_swf_cnt_unit_type_conflict .
      CATCH cx_swf_cnt_elem_def_invalid .
      CATCH cx_swf_cnt_container .
    ENDTRY.

    lv_param_name  = 'IUSER'.  " parameter name of the event
    lv_id          = iuser.

    TRY.
        CALL METHOD lr_event_parameters->set
          EXPORTING
            name  = lv_param_name
            value = lv_id.

      CATCH cx_swf_cnt_cont_access_denied .
      CATCH cx_swf_cnt_elem_access_denied .
      CATCH cx_swf_cnt_elem_not_found .
      CATCH cx_swf_cnt_elem_type_conflict .
      CATCH cx_swf_cnt_unit_type_conflict .
      CATCH cx_swf_cnt_elem_def_invalid .
      CATCH cx_swf_cnt_container .
    ENDTRY.

    TRY.
        CALL METHOD cl_swf_evt_event=>raise
          EXPORTING
            im_objcateg        = cl_swf_evt_event=>mc_objcateg_cl
            im_objtype         = lv_objtype
            im_event           = lv_event
            im_objkey          = lv_objkey
            im_event_container = lr_event_parameters.
      CATCH cx_swf_evt_invalid_objtype .
      CATCH cx_swf_evt_invalid_event .
    ENDTRY.

    COMMIT WORK.
  ENDMETHOD.

Bellow code can be placed in MV45AFZZ user-exit or you can use BADI to call the SET_PARAM method to trigger the workflow.

( Code – 5 )

*** TRIGGER WORKFLOW FROM MV45AFZZ.
*** LV_USER is an Approver who is going to take decision whether SO should be removed from Credit Block or Not.

*** MANUALLY TRIGGER WORKFLOW FOR VKM1
 DATA obj TYPE REF TO zso_approval_exit.
      data lv_user_t type uname.

  CREATE OBJECT obj.
      lv_user_t = |US{ lv_user }|.
      obj->set_params( EXPORTING iso = vbak-vbeln iuser = lv_user_t ).
*** MANUALLY TRIGGER WORKFLOW FOR VKM1


*** CODE TO REMOVE OLD/PENDING WORKFLOW TRIGGERD FOR THE SAME SO.
      lv_srch = |%{ lv_vbeln }|.       "CONCATE % WITH SO NUMBER

      SELECT wi_id wi_aagent wi_cd wi_ct FROM swwwihead INTO TABLE wtab
          WHERE wi_text LIKE lv_srch AND
          ( wi_stat EQ 'READY' OR wi_stat EQ 'STARTED' OR wi_stat EQ 'SELECTED' ) AND
          top_task EQ 'WS90000016'.

       LOOP AT wtab.
          IF wtab-wi_cd LT sy-datum.
            CALL FUNCTION 'SAP_WAPI_ADM_WORKFLOW_CANCEL'
              EXPORTING
                workitem_id  = wtab-wi_id
                actual_agent = wtab-wi_aagent.
          ELSEIF wtab-wi_cd EQ sy-datum AND wtab-wi_ct LE time.
            CALL FUNCTION 'SAP_WAPI_ADM_WORKFLOW_CANCEL'
              EXPORTING
                workitem_id  = wtab-wi_id
                actual_agent = wtab-wi_aagent.
          ENDIF.

        ENDLOOP.

What did you learn from this blog post?

  • You can create a workflow with standard BO events and custom class event by following this prototype. It is also possible to merge multiple workitem in a single workflow .
  • Dynamic agent assignment using Function Module.
  • You can design your own stylish content in mail body using CSS + HTML.
  • Further, you can also add validation in Outbound Delivery and Invoice as well to restrict it without final level approvel.

( Screenshot – 39 )

Do connect me if there is any issue or if I missed some points.

Thanks & Regards,

Rajesh Kalyanji Rajgor