Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member118192
Participant
9,423
Welcome back to this bad romance series of Approve Leave Request from ESS/MSS and Fiori UX. In Part 1 and Part 2. We have established a case and a workflow to run synchronously from both sides.

In this part I will explain you the technical part of the workflow we have just discussed. So get set go!

Technical Part of Leave Request Multi Level Workflow


To cater the customized changes in the workflow, I have created a customized class with few methods to get my logic working.



This is my customized class with a few methods, lets go hold of these quickly.

1. Activity: Set initial approver (I have a method for that) Importing: Request ID, Exporting: Agent (initial approver). Same import export binding is done from method to task and from task to Workflow. Code is as below:
METHOD set_initial_approver.

DATA: lr_request TYPE REF TO cl_pt_req_request,
ls_owner TYPE ptreq_actor_struc_flat,
ls_owner_uname TYPE sysid,
lv_oid TYPE os_guid,
lt_approvers_temp TYPE ptreq_approver_tab,
ls_approvers_temp TYPE ptreq_approver_struc,
lv_item_list_id TYPE ptreq_header-item_list_id,
lv_item_ins TYPE ptreq_items-item_ins,
lv_infotype TYPE infty,
lv_pernr TYPE pernr_d,
lv_awart TYPE pa2001-awart,
lv_uname TYPE syst_uname,
lv_pernr_nxtappr TYPE objektid,
ls_attribs TYPE ptreq_attribs_struc_flat.

* Move request to Globally Unique Identifier
lv_oid = iv_request_id.

* Enqueue the request
CALL FUNCTION 'ENQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
mandt = sy-mandt
request_id = iv_request_id
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.

* Get the request object instance
lr_request ?= ca_pt_req_header=>agent->if_os_ca_persistency~get_persistent_by_oid( lv_oid ).

* Get Owner Details
ls_owner = lr_request->if_pt_req_request~get_owner( ).

lv_pernr = ls_owner-pernr.
ls_owner_uname = ls_owner-user.

CONDENSE ls_owner_uname NO-GAPS.

MOVE ls_owner_uname TO lv_uname.

* Get Att./abs. type
SELECT SINGLE item_list_id
FROM ptreq_header
INTO lv_item_list_id
WHERE request_id = iv_request_id.

IF sy-subrc = 0.

SELECT SINGLE item_ins
FROM ptreq_items
INTO lv_item_ins
WHERE item_list_id = lv_item_list_id.

IF sy-subrc = 0.

SELECT SINGLE infotype subty
FROM ptreq_attabsdata
INTO (lv_infotype, lv_awart)
WHERE item_id = lv_item_ins
AND pernr = lv_pernr.

ENDIF.

ENDIF.

* Get all leave request approvers
CALL FUNCTION 'ZWF_GET_ALL_APPROVERS_LEAVE'
EXPORTING
pernr = lv_pernr
awart = lv_awart
initiator = lv_uname
IMPORTING
et_approvers = lt_approvers_temp.

READ TABLE lt_approvers_temp INTO ls_approvers_temp
INDEX 1.
IF sy-subrc = 0.

lv_pernr_nxtappr = ls_approvers_temp-pernr.

CONCATENATE 'US' ls_approvers_temp-SYS_USER
INTO ev_nxtappr.

CONDENSE ev_nxtappr NO-GAPS.

* Set Next Approver
CALL METHOD lr_request->if_pt_req_request~set_next_processor
EXPORTING
im_actor_type = 'P'
im_plvar = '01'
im_otype = 'P'
im_objid = lv_pernr_nxtappr. " PERNR of Next Approver

IF sy-subrc = 0.
* Provides all the attributes of the request
CALL METHOD lr_request->if_pt_req_request~workarea_version->get_all_attribs
IMPORTING
ex_all_attribs = ls_attribs.

* Create Persistent Database Version
CALL METHOD lr_request->clone_to_old.

* Commit work and wait
COMMIT WORK AND WAIT.

ENDIF.

ENDIF.

* Dequeue the request
CALL FUNCTION 'DEQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
request_id = iv_request_id.

ENDMETHOD.

Code is self-explanatory, ask me in comments if you don’t get anything. I am NOT going to explain FM: ZWF_GET_ALL_APPROVERS_LEAVE because I have my own logic to fetch next approver. You may use your own.

2. Activity: Getting Employee Name is easy. Go, get it from PA0002, pass PERNR.

3. Activity: Approval Process is a standard task TS12300097 SAP use to approve leave request.

4. Condition: Check Approve: Request Status is REJECTED, WITHDRAWN or APPROVED

5. In case of APPROVED: Activity: Get Next Approver (Method: SET_NEXT_APPROVER in my class). Code is well documented, please go through. Import: Request ID, Current Agent) Exporting: Next Approver. Same binding is done from Method to Task and from Task to WF.
METHOD set_next_approver.


DATA: lr_request TYPE REF TO cl_pt_req_request,
ls_owner TYPE ptreq_actor_struc_flat,
ls_owner_uname TYPE sysid,
lv_oid TYPE os_guid,
lt_approvers_temp TYPE ptreq_approver_tab,
ls_approvers_temp TYPE ptreq_approver_struc,
lv_item_list_id TYPE ptreq_header-item_list_id,
lv_item_ins TYPE ptreq_items-item_ins,
lv_infotype TYPE infty,
lv_n_agent TYPE swp_agent,
lv_index TYPE sy-index,
lv_pernr TYPE pernr_d,
lv_awart TYPE pa2001-awart,
lv_uname TYPE syst_uname,
lv_pernr_nxtappr TYPE objektid,
lv_req_notice TYPE tim_req_notice,
ls_attribs TYPE ptreq_attribs_struc_flat.

** wait for 60 Seconds for completion of all DB commits
WAIT UP TO 60 SECONDS.

* Move request to Globally Unique Identifier
lv_oid = iv_request_id.

* Enqueue the request
CALL FUNCTION 'ENQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
mandt = sy-mandt
request_id = iv_request_id
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.

* Get the request object instance
lr_request ?= ca_pt_req_header=>agent->if_os_ca_persistency~get_persistent_by_oid( lv_oid ).

* Get Owner Details
ls_owner = lr_request->if_pt_req_request~get_owner( ).

lv_pernr = ls_owner-pernr.
ls_owner_uname = ls_owner-user.

MOVE iv_n_agent TO lv_n_agent.

REPLACE FIRST OCCURRENCE OF 'US' IN lv_n_agent
WITH space.

CONDENSE: ls_owner_uname NO-GAPS,
lv_n_agent NO-GAPS.

MOVE ls_owner_uname TO lv_uname.

* Get Att./abs. type
SELECT SINGLE item_list_id
FROM ptreq_header
INTO lv_item_list_id
WHERE request_id = iv_request_id.

IF sy-subrc = 0.

SELECT SINGLE item_ins
FROM ptreq_items
INTO lv_item_ins
WHERE item_list_id = lv_item_list_id.

IF sy-subrc = 0.

SELECT SINGLE infotype subty
FROM ptreq_attabsdata
INTO (lv_infotype, lv_awart)
WHERE item_id = lv_item_ins
AND pernr = lv_pernr.

ENDIF.

ENDIF.

* Get all leave request approvers
CALL FUNCTION 'ZWF_GET_ALL_APPROVERS_LEAVE'
EXPORTING
pernr = lv_pernr
awart = lv_awart
initiator = lv_uname
IMPORTING
et_approvers = lt_approvers_temp.

READ TABLE lt_approvers_temp TRANSPORTING NO FIELDS
WITH KEY sys_user = lv_n_agent.

lv_index = sy-tabix.
ADD 1 TO lv_index.

READ TABLE lt_approvers_temp INTO ls_approvers_temp
INDEX lv_index.
IF sy-subrc = 0.

CONCATENATE 'Request forwarded to' ls_approvers_temp-name
INTO lv_req_notice
SEPARATED BY space.

lv_pernr_nxtappr = ls_approvers_temp-pernr.

CONCATENATE 'US' ls_approvers_temp-sys_user
INTO ev_nxtappr.

CONDENSE ev_nxtappr NO-GAPS.

* Set Next Approver
CALL METHOD lr_request->if_pt_req_request~set_next_processor
EXPORTING
im_actor_type = 'P'
im_plvar = '01'
im_otype = 'P'
im_objid = lv_pernr_nxtappr. " PERNR of Next Approver

IF sy-subrc = 0.

* Provides all the attributes of the request
CALL METHOD lr_request->if_pt_req_request~workarea_version->get_all_attribs
IMPORTING
ex_all_attribs = ls_attribs.

* Create Persistent Database Version
CALL METHOD lr_request->clone_to_new.

* Commit work and wait
COMMIT WORK AND WAIT.

ENDIF.

ENDIF.

* Dequeue the request
CALL FUNCTION 'DEQUEUE_EPTREQ'
EXPORTING
mode_ptreq_header = 'S'
request_id = iv_request_id.

ENDMETHOD.

6. Activity: Set Status Send. Importing: Request ID, Exporting: New Status



7. Activity: Set Status Approved. Importing: Request ID, Exporting: New Status



8. Activity: Get Current Status. Latest status of the request from PTREQ_HEADER

9. Loop Condition



Rest is standard. Email and SMS logic is all over internet. Find and send them.

Now we are done with the Workflow development and explanation. Technical part is done as well, if you have any question, please feel free to comment.

Leave Request Approved but dump in ST22


Since, we are done with the workflow. Pretty easy yeah? But where is the challenge.

Go to Step number 6: Change Status to SEND. Somehow SAP don’t change this status and throws and dump. This dump comes whenever the Approve button is pressed either from Fiori or ESS/MSS. Why this dump occurs? Let's catch that! I have analyzed this thing and I have concrete answer to this (this is the pain area for most of us).

Dump details are as follows:
Runtime Errors: UNCAUGHT_EXCEPTION

Exception: CX_OS_DB_INSERT

ABAP Program: CA_PT_REQ_HEADER==============CP

Just putting in a screenshot just to be sure.


Above dump says that there an expectation when inserting in some table? Which table? Let’s analyze.



Dump occurred in this method: MAP_SAVE_TO_DATABASE line: 152. This dump occurred when I tried to change the Status from APPROVE to SENT in my custom (CHANGE_STATUS_SENT) method.

Scenario for CX_OS_DB_INSERT Dump



  1. Status didn’t get changed

  2. There was no next approver

  3. Loop found the current status of request as SENT, loop condition met.

  4. Leave Request again sent to the same approver again!


How irritating for the user who has just approved the leave request and came back to him! Wow! Great! Amazing! Imagine this happening with 1800 users!

Why Dump Occurred


Why this dump came? Because by default sometimes I don’t know how. SAP put an entry of status SENT when leave is approved (specially in case of multi-level). That SENT row is already there in table PTREQ_HEADER and I am trying to insert the same row. So, it says I have that row already which you are trying to insert and dumps! Let me show you the table.


You see above? All rows are set to SENT. Why? Because of that nasty dump!

Solution to dump: Runtime Errors: UNCAUGHT_EXCEPTION. Exception: CX_OS_DB_INSERT. ABAP Program: CA_PT_REQ_HEADER==============CP


You could have noticed that I have put a WAIT statement in my methods, yeah because let SAP do its entries in the said table then I will do my trick. So, let SAP put a SENT status in the table after the request is approved. Then I am creating a new row with status APPROVED then SENT again.

Leave Request posted but the Document in PTARQ is in Error


This is an easy catch. If any document goes in to error (remember, not talking about workflow).



Just run the following two reports:

  1. RPTARQERR for less than 50 employees

  2. RPTARQERR_ALL for more


That's all folks! I hope you have enjoyed this series and learned a lot. Please let me know if you have any queries.

Thank you!
9 Comments
Labels in this area