Blog Post created by TMACUL Champion on Jan 1, 2016

Close attached incidents

From SDU

Jump to: navigation, search


I was asked by the business folk in my company to come up with a way to close all attached incidents (just like the "Actions, Close All Children").

STEP I: I started by creating the following object in WSP:

//////////////////////////////////////////////////////////////////////// // Factory:   z_cr_close_att_inc ////////////////////////////////////////////////////////////////////////   OBJECT z_cr_close_att_inc { ATTRIBUTES z_cr_close_att_inc { description STRING 4000 REQUIRED; owning_pr SREL pr REQUIRED; res_code SREL resocode; root_cause SREL rc; last_mod_dt DATE { ON_CI SET NOW; }; last_mod_by SREL cnt { ON_CI SET USER; ON_NEW DEFAULT USER; }; };   FACTORY z_cr_close_att_inc { STANDARD_LISTS { MLIST OFF; RLIST OFF; }; REL_ATTR id; COMMON_NAME description; }; TRIGGERS { POST_CI z_close_att_inc( persistent_id ) 1040 FILTER (EVENT("INSERT") ); }; }; /////////////////////////////////////////////////////////////////////////////////////////// // End of object code //////////////////////////////////////////////////////////////////////////////////////////

The only two required field here are the "owning_pr" (problem ticket srel) and the "description" (this becomes the solution.  The other fields are just fields in the incidents that we will update at the same time we close them.

STEP II: Next, I created a detail form for the above object in WSP. I used the standard detail template but made the following changes:

                   1. Search for <PDM_MACRO NAME=dtlForm factory="z_cr_close_att_inc> and change it to <PDM_MACRO NAME=dtlForm factory="z_cr_close_att_inc" button=false> (this keeps the default "Save, Cancel, Update" buttons from showing up). 2.  Next, I added my own buttons. This code codes in between the line above and the <PDM_MACRO NAME=dtlStart> tag: 
ImgBtnRow(); ImgBtnCreate("btn001","OK[k]","SaveAndClose();detailSave();",true, 120); ImgBtnCreate("btncncl", "Cancel[n]", "cancel_update('$prop.form_name_2','$','show_main_detail.htmpl')", true, 120); ImgBtnCreate("btn003", "Reset[R]", "pdm_reset()", true, 120); ImgBtnEndRow();

(the reason I did this is I wanted the detail from to close as soon as the "OK" button was clicked.)

Step III: Next, I added the following code the the menubar_sd.htmpl right below the "Actions, Close All Children" link:

<PDM_OBJECT> if ( w.propFormName2 == "pr" ){ <PDM_MACRO name=menuItem label="Close All Attached Incidents" function="ahdtop.create_new('z_cr_close_att_inc',0,'','','PRESET=owning_pr:\" + w.argPersistentID + \" ')"> } </PDM_OBJECT>
               (It will only show up if the ticket you are in is a Problem) 

Step IV: The Spel code. This code will load the fields in the detail_z_cr_close_att_inc.htmpl form into temp variables, parse through all attached incidents, update the fields, close the incident, and log a solution. At the very end, it will    delete the newly created z_cr_close_att_inc object  so you don't have to worry about it filling up your DB. I have commented the code throughout:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MBRAEMER - 02/18/11 - Created - This code will all incidents where the problem field = the submitted problem ticket,  //                                  update the passed mandatory fields, then close-resolve the incidents. Then call a sleep, //                                  then delete the z_cr_close_att_inc ticket. //                       TRIGGER - POST_CI ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// z_cr_close_att_inc::z_close_att_inc(...) { string errmsg, method, where_clause; int count, i, debugging_f;   method = "z_cr_close_att_inc::z_close_att_inc()"; count = 0; debugging_f = 1;   if ( debugging_f == 1) { logf(SIGNIFICANT, "argv3 = %s", argv[3]); }   //get the z_cr_close_att_inc object send_wait(0, top_object(), "call_attr", "z_cr_close_att_inc", "dob_by_persid", 0, argv[3], NULL, NULL); if ( msg_error()) { errmsg=format("Error in z_cr_close_att_inc dob_by_persid: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; } object this_crClAttIn; this_crClAttIn = msg[0];   //below will be the variables from the this_crClAttIn that will be passed to each incident being updated string pr_persid, parent_description; int rescd, this_rc;   pr_persid = this_crClAttIn.owning_pr; parent_description = this_crClAttIn.description;   rescd = this_crClAttIn.res_code; this_rc = this_crClAttIn.root_cause;     where_clause = format("problem = '%s' AND active = 1", pr_persid);   if ( debugging_f == 1) { logf(SIGNIFICANT, "pr_persid = %s", pr_persid); logf(SIGNIFICANT, "parent_description = %s", parent_description); logf(SIGNIFICANT, "rescd = %d", rescd); logf(SIGNIFICANT, "where_clause = %s", where_clause); }   object attInc_domset; send_wait(0, top_object(), "call_attr", "cr","sync_fetch", "DYNAMIC", where_clause,  -1, 0); if (msg_error()) { errmsg=format("cr sync_fetch: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; } attInc_domset = msg[0]; count = msg[1];   if ( debugging_f == 1) { logf(SIGNIFICANT, "count = %d", count); }   //if there are no attached incidents, get the heck outta dodge if (count == 0){ return; }   i=0;   //cycle through all incidents in the above created domset for (i; i<count; i++) { if ( debugging_f == 1) { logf(SIGNIFICANT, "i = %s", i); } send_wait(0, attInc_domset, "dob_by_index", "DEFAULT", 0, 0); if (msg_error()) { errmsg=format("error getting dob_by_index: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; }   object this_here_inc; this_here_inc = msg[0];   //need to grab this incidents persid and current status for use later string this_inc_persid, this_status_cd; this_inc_persid = this_here_inc.persistent_id; this_status_cd = this_here_inc.status;   if ( debugging_f == 1) { logf(SIGNIFICANT, "this_inc_persid = %s", this_inc_persid); logf(SIGNIFICANT, "this_status_cd = %s", this_status_cd); }   //if the incident is not already closed-resolved, then update, close and log comment. if ( this_status_cd != 'CL'  ) { //check out the incident so you can update the mandatory fields object group_leader; send_wait(0, top_object(), "get_co_group"); if (msg_error()) { errmsg=format("error getting group_leader: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; } group_leader = msg[0];   send_wait(0, group_leader, "checkout", this_here_inc); if (msg_error()) { errmsg=format("error on checkout: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; }   //Now set all of the necessary fields send_wait(0, this_here_inc, "call_attr", "resolution_code", "set_val", rescd , "SURE_SET"); send_wait(0, this_here_inc, "call_attr", "rootcause", "set_val", this_rc , "SURE_SET");   //last, set status of ticket to closed-resolved send_wait(0, this_here_inc, "call_attr", "status", "set_val", "CL" , "SURE_SET");   //now check back in send_wait(0, group_leader, "checkin"); if (msg_error()) { errmsg=format("error on checkin: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; }   //now, sleep and create a new activity to log the solution      sleep(3); send_wait(0, top_object(), "get_co_group"); if (msg_error()) { errmsg=format("error getting group_leader: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; } group_leader = msg[0];   send_wait( 0, top_object(), "call_attr", "alg", "get_new_dob", NULL, NULL, group_leader); if (msg_error()) { errmsg=format("error creating new record: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; }   object new_alg_obj; new_alg_obj = msg[0];   //set all of the attributes of the new alg object   new_alg_obj.action_desc = "log solution text"; new_alg_obj.call_req_id = this_inc_persid; new_alg_obj.description = parent_description; new_alg_obj.time_spent = 0; new_alg_obj.type = "SOLN";   //now check the new object in send_wait(0, group_leader, "checkin"); if (msg_error()) { errmsg=format("error on checkin: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; } }     //exit loop      }   //Now it's time to sleep and delete this object sleep(3);   int this_id; string delete_clause;   this_id =; delete_clause = format("id=%d", this_id);   if ( debugging_f == 1) { logf(SIGNIFICANT, "this_id = %d", this_id); logf(SIGNIFICANT, "delete_clause = %s", delete_clause); }   send_wait(0, top_object(), "call_attr", "api", "delete_wc", "z_cr_close_att_inc", delete_clause, NULL); if (msg_error()) { errmsg=format("error on delete: '%s'",msg[0]); logf(ERROR,method+errmsg); set_return_data(errmsg); set_error(-1); return -1; }     } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of z_cr_close_att_inc::z_close_att_inc() ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

That's pretty much it.

Retrieved from ""


This page was last modified 14:46, 22 February 2011.  This page has been accessed 4,144 times.  Content is available under Attribution-Noncommercial-Share Alike 3.0 Unported.   Disclaimers