I
often see clients request the ability to copy task records. There are a variety of ways to implement copying functionality and each method has its trade-offs. Templates, a checkbox field combined with a business rule, or even activating the ‘Insert’ UI action buttons for the task table are all methods that I’ve seen.
In my experience, the best method is to create a brand new UI action button on the table in question. Below is a script I created to add a ‘Copy’ button to the ‘Change request’ form. This script should be pretty complete for most implementations. You may just have to customize a few lines to copy over the appropriate fields. The main advantage that this script has over other methods is that it also copies all of the ‘Affected CI’ records, Change tasks, and attachments for both the Change request and all Change tasks.
Name: Copy change
Form button: True
Table: Change Request
Condition: gs.hasRole(“itil”) && current.isValidRecord()
Script:
var newChange = new GlideRecord('change_request');
newChange.initialize();
newChange.short_description = current.short_description;
newChange.requested_by = current.requested_by;
newChange.category = current.category;
newChange.type = current.type;
newChange.assignment_group = current.assignment_group;
newChange.assigned_to = current.assigned_to;
newChange.description = current.description;
newChange.risk = current.risk;
newChange.urgency = current.urgency;
newChange.implementation_plan = current.implementation_plan;
newChange.test_plan = current.test_plan;
newChange.backout_plan = current.backout_plan;
newChange.insert();
//Copy attachments for this change
if (typeof GlideSysAttachment != 'undefined')
GlideSysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
else
Packages.com.glide.ui.SysAttachment.copy('change_request', chgID, 'change_request', newChange.sys_id);
copyTask();
copyCI();
gs.addInfoMessage('Change ticket ' + newChange.number + ' created.')
action.setRedirectURL(newChange);
function copyTask() {
//Find the current change tasks and copy them
var tasks = new GlideRecord('change_task');
tasks.addQuery('change_request', current.sys_id);
tasks.query();
while(tasks.next()){
var taskID = tasks.sys_id.toString();
//Copy the task record to a new task record
var newTask = new GlideRecord('change_task');
newTask.initialize();
newTask.change_request = newChange;
newTask.order = tasks.order;
newTask.short_description = tasks.short_description;
newTask.description = tasks.description;
newTask.assignment_group = tasks.assignment_group;
newTask.assigned_to = tasks.assigned_to;
newTask.insert();
//Copy attachments for this task
if (typeof GlideSysAttachment != 'undefined')
GlideSysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
else
Packages.com.glide.ui.SysAttachment.copy('change_task', taskID, 'change_task', tasks.sys_id);
}
}
function copyCI() {
//Copy over the affected CI list
var currentCI = new GlideRecord('task_ci');
currentCI.addQuery('task', current.sys_id);
currentCI.addNullQuery('u_ci_group'); //Added to ensure that copying does not duplicate Group CIs
currentCI.query();
while(currentCI.next()){
var newCI = new GlideRecord('task_ci');
newCI.initialize();
newCI.task = newChange.sys_id;
newCI.ci_item = currentCI.ci_item;
newCI.insert();
}
}
This is great… Thanks. Is there something that I could add to this UI Action that would bypass any missing required fields during the copy process? This code appears to try to save the current change prior to making the copy.
Hi..this is awesome, Thanxx a ton..! but unfortunate this is not my current requirement!
My requirement is to relate multiple problem tickets with one Change request record..however currently one PRBXXX is related with one CHGXXX record.
I have found UI action, and business rule where changes need to make, but not able to get different logics..
Any ideas to get this done !
Out of box, a problem can be related to a single change request, but a change request can be related to many problem tickets. Any time you have a reference field on a form, it represents a one-to-many relationship with the table it references. With problem-change, you have a reference field on the problem form, and a related list on the change form. You need to personalize the change request related lists and add the problems list.
Hi Mark,
Is there a way to do this exact action but not automatically insert the record. Require the user to submit after filling out some Change Request specific fields on the new record which is displayed after pressing the UI Action?
Thanks – Scott
There isn’t with this method. There is another way of doing the same thing that would allow you to select a change request to copy from (from a reference field). If you were to use this method, then you could put that field on a change request form with the few fields you needed to override, require those fields to be filled in, and then copy those values over the newly-created change.
I’ve been meaning to post that method for a while. I’ll try to post it next week.
Thanks for the info and Help!
No problem. Here’s a link to the article describing the other methods.
https://servicenowguru.wpengine.com/system-ui/ui-action…
Mark – do you know how I could change your code to NOT insert the record until the required fields are filled out by user? (similar to how the Global ‘New’ UI Action works)
My problem is people will copy a Change with my UI Action, then close out their browser or navigate to another area of ServiceNow and not fill in my required fields..
Thx..
@scott – You can do a change copy without an insert, but you have to pass all of the information over the URL in a ‘sysparm_query’ parameter and then redirect the user to the URL in order to make it work. With a full record copy, that’s usually way too much information to handle that way. If you want to give it a try, you can construct your URL as shown here…
https://servicenowguru.wpengine.com/service-now-general-knowledge/populating-default-values-url-module/
I’m going to recommend we enforce policy/procedures (let the wrist slapping begin!) Thanks Mark for the info..
When such a UI action is executed my browser shows and error – “current not defined”, and nothing is written to the record I initialized.
I’m not sure what might be the issue. These scripts have been tested and verified before. Please try copying and pasting from here and testing in a ServiceNow demo instance.
Hello Mark. The script is absolutely perfect and I love it. One question or maybe just guidance…..In our organization, we have the user first specify what type of change they are creating. This is using an interceptor. We have separate work flows for each change type. It is common for a user to create an Emergency Change when they should have created an Urgent change. We also make the Change Type read only to keep the user from selecting one type and changing it to another and possibly bypassing parts of our process.
My question is, how can I incorporate this script but allow the user to select the Change Type so that the appropriate work flow is associated.
Thanks again.
There are ways to do that, but it’s actually fairly complicated. I’ve seen some discussions on the ServiceNow community about this, but haven’t really seen anything that covers all of the bases outside of what we do at Crossfuze in our turnkey change product.
We allow the user to do 2 things. The first is that they can change the ‘Type’ field as long as the change is in a draft state. This allows for some flexibility in selecting the change type before you get into the full workflow. The second thing we’ve done is create a custom interceptor concept that routes the user to an intermediate record producer form that allows us to ask for details about the change…type, etc. before actually creating the change. Since it’s a part of our proprietary code base, I can’t share the details, but I would be willing to do a demo of the solution for you if you’d like to take a look.
Thank you Mark for the helpful script!
Here are the corrections that I had to make for this script to work as intended:
– When setting the change_request on the new task, a sys_id of the task should be used:
==> newTask.change_request = newChange.sys_id;
– In the code for copying task attachments the second sys_id should be of the new task:
if (typeof GlideSysAttachment != ‘undefined’)
GlideSysAttachment.copy(‘change_task’, taskID, ‘change_task’, newTask.sys_id);//Calgary and up
else
Packages.com.glide.ui.SysAttachment.copy(‘change_task’, taskID, ‘change_task’, newTask.sys_id);//pre Calgary
Thank you again!
Any way to copy the varaible information as well if it was generated via a Record Producer. Currently variable information not copied over.
This can certainly be done, you would need to perform a query against the ‘question_answer’ table using a similar routine to the one found in the sample script above and perform inserts of any records found.
Thanks Mark for the quick reply. I thought that would be the case as well and wondered if there was any other quick way of doing this. Will give this a try 🙂
Mark,
This works great on smaller changes, but we have run into an issue where we bump up against the UI transaction quota limits when we have many CI’s associated with the change. In our test example, we had 365 related CI’s and only were able to copy about 340 before it timed out.
Any suggestions on how to avoid this?
Hi Steve, I’m not sure how you could deal with that. You’ll probably need to contact ServiceNow support to investigate.