Best Practice for Managing Asset State \ CI Status

Robin Hearne
Tera Expert

I have a question for all you process experts out there.   Before I begin, this isn't about what you could do, this is about what is the best thing to do from a process and tool perspective.   I always try to be guided by what ServiceNow provides out-the-box and try to understand how the product was intended to be used before making any changes.

We are planning our Asset and Config Management deployment and are trying to make a decision on how to manage Asset state \ CI status.   The primary consideration is how the desktop support techs will update the record(s) to show when the asset\CI is in use, in maintenance, returned to a stock room etc.

The OTB experience is that the Status field isn't even exposed on the CI form, which leads me to think that the intended use is to manage it there and let the mapping feature take care of updating the CI status.   Also, previous ServiceNow documentation states "As a best practice, ServiceNow, Inc. recommends updating status on the asset form" (although this is from 2015 and this doesn't seem to be included in the latest documentation).

However....

This somewhat contradicts ISO\ITIL "best practice" which recommends that IMAC is part of the Configuration Management process, rather than the Asset Management process.   Also, the ITIL role only has read permission to the Asset record, so the desktop support techs would need the 'asset' role, which is arguably inappropriate given that they aren't really involved in the Asset Management process (just Configuration Management).   From a tool perspective, in order to manage IMAC in Configuration Management would require a number of changes on the CI form, such as adding the Status, plus exposing other fields such as Location, Stock rooms etc.   Which whilst simple to do, still suggest to me that this isn't how ServiceNow was intended to be used.

I'm leaning towards managing Asset State and either assign the Asset role or add an ACL to allow ITIL users to update the Asset State, Location etc, but I'd welcome other options before making a decision.

bsweetser - Hoping you might be able to give your opinion on this?

Thanks in advance.

Robin

1 ACCEPTED SOLUTION

Community Alums
Not applicable

Hi Robin,



Depending on the approach used to drive the change of State, yes, you could have a pop-up to capture the required information, similar to the Consuming of a Consumable. It really depends on the process you are looking to drive, though. You can always consider other methods to capture the information. For example, if you launch a process to retire a piece of hardware, that process may include a step to return the hardware to a stockroom to be prepared for disposal. Rather than prompting for the Stockroom, you might leverage Location information from the user record to automate the selection of the closest drop off or disposal Stockroom. When you identify how you want to begin the process, consider the information you need and how you can get that information. If it is possible to get that information through some automated means, even better.



Ben


View solution in original post

22 REPLIES 22

Thanks Jens, that was indeed one of the many videos that I viewed in my research for this project.



Just to wrap this up.   I implemented Ben's suggestion of using a UI Action for 'Return to Stock'.   The UI Action launches a UI Page which captures the Stock Room and Substate.   We went live a few weeks ago and this is working very well.



We also took a similar approach for assigning Assets\CIs to users.   We created a 'Change assignment' UI Action to collect the new assignment details rather than have the user change the individual fields on the form (we made those fields read-only to drive a consistent process).   The UI Page prompts for the User, Location (optional), Effective date (used for populating 'Assigned' date) and also the ticket reference.   The latter is used to automatically create a task_ci record as a quicker and more consist (i.e. more likely to be done!) method to link the CI to the Requested Item.



So now Service Desk and Desktop groups can do almost everything they need during the active life of an asset via two links on the CI form.



Thanks to everyone for their contributions and suggestions and for helping my project be successful!



Regards,



Robin


Community Alums
Not applicable

Awesome, Robin! So glad to hear this worked out for you. Well done!



Ben


Hi Robin,


I'm looking to do something similar on my implementation - enable the stockrooms from within a CI.



Would you be able to share your UI Action 'Return to Stock'?



Thanks


Sure.



Here's the script for the UI Action:


function openPopUp(){




      var dialogClass = window.GlideModal ? GlideModal : GlideDialogWindow;


      var dialog = new dialogClass("return_to_stock");


      dialog.setWidth("600");


      dialog.setTitle("Return Asset to Stock");


      dialog.setPreference("sysparm_sys_ids", g_form.getUniqueValue());


      dialog.render(); // Open the dialog box



}



And for the UI Page 'return_to_stock'...



HTML:


<g:ui_form>


<input type="hidden" id="cancelled" name="cancelled" value="false"/>


<input type="hidden" name="ci_sys_ids" id="ci_sys_ids" value="${sysparm_sys_ids}"/>


<!-- Set up form fields and labels -->


<table width="100%">


<tr>


<td>


<div class="form-group form-horizontal">


<div class="col-md-4 text-right">


<g:form_label> ${gs.getMessage('Stock room')} </g:form_label>


</div>


<div class="col-md-8">


<g:ui_reference name="stock_room" id="stock_room" table="alm_stockroom" query="type!=e2aa2b3f3763100044e0bfc8bcbe5dde^ORtypeISEMPTY" completer="AJAXReferenceCompleter" columns="name;location"/>


</div>


</div>


</td>


</tr>


<tr style="height: 4px"><td></td></tr>


<tr>


<td>


<div class="form-group form-horizontal">


<div class="col-md-4 text-right">


<g:form_label> ${gs.getMessage('Sub State')} </g:form_label>


</div>


<div class="col-md-8">


      <select name="sub_status" id="sub_status">


              <option value="">${gs.getMessage('-- None --')}</option>


              <g2:evaluate var="jvar_item" expression="


                var gr = new GlideRecord('sys_choice');


                gr.addQuery('element', 'substatus');


                gr.addQuery('dependent_value', '9');


                gr.addQuery('name', 'alm_asset');


gr.addQuery('value','!=', 'reserved');  


gr.addQuery('value','!=', 'pre_allocated');  


gr.addQuery('inactive', 'false');


                gr.addQuery('language', 'en');


                gr.orderBy('sequence');


                gr.query();


                "/>


              <j2:while test="$[gr.next()]">


                      <option value="$[gr.value]">$[gr.label]</option>


              </j2:while>


      </select>


</div>


</div>


</td>


</tr>


<tr id="dialogbuttons">


<td colspan="8" align="right">


<div class="modal-footer">


              <button class="btn btn-primary   action_context edit-close pull-right" type="submit" id="submit" onclick="return onSubmit();">${gs.getMessage('OK')}</button>


              <button class="btn btn-default   action_context edit-close pull-right" type="submit" id="cancel" onclick="return onCancel();">${gs.getMessage('Cancel')}</button>


</div>


</td>


</tr>


</table>


</g:ui_form>


Client Script:


function onCancel() {


var c = gel('cancelled');


c.value = "true";


GlideDialogWindow.get().destroy();


jslog('Return to stock - Cancelled');


}




function onSubmit() {


jslog('Return to stock - Submitted');


if (gel('sub_status').value == '') {


alert("${JS:gs.getMessage('Please select a Sub Status')}");


return false;


}


else if (gel('stock_room').value == '') {


alert("${JS:gs.getMessage('Please select a Stockroom')}");


return false;


}


else {


var c = gel('cancelled');


c.value = "false";


return true;


}


}



Processing Script:



if(cancelled == "false"){


updateAssets();


}


var urlOnStack = GlideSession.get().getStack().bottom();


response.sendRedirect(urlOnStack);




function updateAssets() {


try {


var gr = new GlideRecord('alm_hardware');


gr.addQuery('ci', 'IN', ci_sys_ids);


gr.query();


while (gr.next()) {


gr.install_status = 6;


gr.substatus = sub_status;


gr.stockroom = stock_room;


gr.u_place = '';


gr.install_date = '';


gr.assigned_to = '';


gr.location = gr.stockroom.location;


gr.update();


gs.addInfoMessage(gs.getMessage('Asset {0} returned to stock.', [gr.display_name]));


}


var update_ct = gr.getRowCount();


if (update_ct > 0) {


if (update_ct > 1) {


gs.addInfoMessage(gs.getMessage('{0} assets returned to stock.', [update_ct]));


}


}


else{


gs.addInfoMessage(gs.getMessage('No assets returned to stock.'));


}


}


catch(err){


gs.addInfoMessage('Exception: ' + err);


}


}



We also have a List Choice UI Action which uses the same UI Page but the script in the UI Action is slightly different:



function openListReturnToStockPopUp(){


var selSysIds = g_list.getChecked();


      var dialogClass = window.GlideModal ? GlideModal : GlideDialogWindow;


      var dialog = new dialogClass("return_to_stock");


      dialog.setWidth("600");


      dialog.setTitle("Return Asset to Stock");


dialog.setPreference('sysparm_sys_ids', selSysIds);


      dialog.render(); // Open the dialog box


}



Hope this helps.



Robin


Legend, thanks!