
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 06-23-2025 07:49 AM
Problem statement
As part of the out-of-the-box (OOTB) solution for Case Management in Supplier Lifecycle Operations (SLO), it does not currently exist any mechanism for the requestors to review and validate the resolution of their cases before closure. There is currently no review step for requestors to confirm or reject case resolutions before closure, leaving them with no control over the final outcome. As a result, requestors are often uncertain whether their issues have been fully addressed, leading to dissatisfaction, reduced trust in the process, and an increase in case reopenings.
In a similar way, Fulfillers (such as Helpdesk agents) currently lack the ability to transition cases into an intermediate state, before closure. Once a case is resolved, their only option is to mark it as completed, with no mechanism to ask requestors for review or confirmation, with the consequence of having unresolved issues and increased duplicate case re-openings.
Solution
This article is aimed at providing a possible solution for this problem. It is obviously not the only possible solution, but it tries to meet the business necessities with the minimum effort and impact on an instance.
The general idea consists of adding a new 'Resolved' state in the Supplier case table, and once that state is reached, the system automatically generates a new Supplier task for the requestor, so that they can either accept the resolution or re-open the case to provide the expected resolution.
In order to implement it in the system, the following steps must be taken:
Action Type for Supplier Task
First of all, a new 'Action type' must be created in the Supplier Task [sn_slm_task] table, so that requestors can use it to accept or reject the solution proposed to their case.
To do it, access to the dictionary of that field (action_type_for_task), and create a new choice entry with the following details:
Label = Case resolution; Value = case_resolution; Sequence = 2000
Set Task type default due date
One OOB feature it must be considered when dealing with Supplier tasks, is the due date, which based on an existing data policiy, is mandatory for any state other than 'Draft'. The same happens with other fields in this table, such as Description, Assigned to and Action Type.
So, in order to make sure this value is correctly auto-populated when a new 'Case resolution' supplier task is created, the 'Supplier Task Default Due Date' decision table must be updated to include a new entry for the new action type created in the previous step. The value might depend on how much time we want to give the requestors to provide an answer. In the example below, we are setting up a due date for this action type of 5 days after its creation:
Create 'Resolved' state
A new state choice must be created in the Supplier Case [sn_slm_case] table, so that it's available to control the expected behaviour.
Accessing the 'State' (state) field dictionary, a new entry must be created with the following details:
Table = sn_slm_case; Label = Resolved; Sequence = 139; Value = 1010 (I normally tend to set much higher values than the OOB ones, just in case the new ServiceNow versions come with new case types, to reduce the probability of a duplicated value).
Disable 'Complete' button
The OOB 'Complete' UI Action available in Supplier Case [sn_slm_case] table must be either disabled (Active = false), or changed on its conditions, so that it does not appear available for the Agents to be used and automatically complete the Case by clicking on it, at least for the case types we want to implement this feature for.
Create 'Resolve' button
A new 'Resolve case' UI Action must be created in the Supplier Case [sn_slm_case] table with the following details:
- Condition: current.isValidRecord()&¤t.canWrite()&& (current.state==30||current.state==80);
- Script:
var sloUtils = new sn_slm.SupplierCommonUtil();
var closeNotes = current.getValue("close_notes");
if (!gs.nil(closeNotes)) {
var supplierTaskObj = {
"assigned_to": current.getValue("opened_by"),
"parent": current.getUniqueValue(),
"action_type_for_task": "case_resolution",
"state": 1,
"opened_by": gs.getUserID(),
"supplier": current.getValue("supplier"),
"description": gs.getMessage("By completing this task, you are accepting the resolution of this case, and it will be automatically closed. Otherwise, please provide a reason for reopening the Case."),
"short_description": gs.getMessage("Accept resolution for ") + current.getValue("number"),
"task_audience": "external"
};
var supplierTaskId = sloUtils.createSupplierTask(supplierTaskObj, false);
if (supplierTaskId) {
current.state = 1010;
current.update();
}
} else {
gs.addErrorMessage(gs.getMessage("Close notes must be added before resolving the case."));
}
Clone 'Supplier Task To-Do' widget
In order to make sure that Supplier contacts can have this feature available from the Supplier Collaboration Portal, a new version of the OOB 'Supplier Task To-Do' widget must be created and adapted. With this new version, the Suppliers will be able to either accept or reject the resolution of a Case, by using the Task generated in the previous step, including two buttons (Accept resolution, Re-open case) and a free-text field to specify the reason for their rejection in that scenario, so that Agents can get proper details about why the case is being reopened.
So, a clone of the OOB widget should be created, and modified with the following details:
- Body HTML Template: The following code should be added at the bottom of this field, right before the last </div> command. It contains the free-text field to specify the reason to reopen the case, and the two buttons to either accept or reject the resoution proposed:
<!-- Accept / Reject resolution for case -->
<div class="btn-float" ng-if="!c.data.task.closedState && c.data.task.task_type == 'case_resolution'">
<input type="text" id="reopen-case-reason" class="form-control ng-pristine ng-valid ng-scope ng-valid-maxlength ng-not-empty ng-touched"/>
<button class="btn btn-primary link-button font-primary" ng-disabled='!(c.data.task.canWrite)' ng-click="c.completeTask(c.data.task.table, c.data.task.sys_id);" data-toggle="tooltip" title="${Accept solution}">
${Accept solution}
</button>
<button class="btn btn-primary link-button font-primary" ng-disabled='!(c.data.task.canWrite)' ng-click="c.reopenCase(c.data.task.table, c.data.task.sys_id);" data-toggle="tooltip" title="${Re-open case}">
${Re-open case}
</button>
</div>
- CSS: The new fields can be stylized as required. In this case, we are just simply adding some margin between the free-text field for the rejection reason and the buttons:
#reopen-case-reason{
margin-bottom: 15px;
}
- Server script: It must be modified to include the following piece of code to correctly process the Task when the requestor accepts the resolution. In that case, the case state is automatically set to 'Closed complete' (value is 60)
// Case resolution
if (input.actionType === 'case_resolution' && input.sysId) {
var caseGr = new GlideRecord("sn_slm_case");
if(caseGr.get(supTaskGR.parent)){
caseGr.setValue("state",60);
caseGr.update();
}
}
Likewise, the following code must also be included in order to correctly process the rejection of the resolution, and the case must be reopened (The system automatically sets the state to 'Open', whose value is 110, and updates the case with a comment including the reason for solution rejection):
// Case resolution: Set Case back to Open state and close the Task as Incomplete, with comments
if (input && input.action == "reopenCase") {
data.success = false;
var actionTable = '';
var actionId = '';
if (input.res) {
actionTable = '' || input.res.table;
actionId = '' || input.res.sys_id;
}
var caseGr = new GlideRecord("sn_slm_case");
if(caseGr.get(supTaskGR.parent)){
caseGr.setValue("state",110);
caseGr.comments = "Reopening Case from Supplier with reason: " + input.reopenReason;
caseGr.update();
}
supTaskGR.setValue("state", CLOSE_COMPLETE_STATE);
supTaskGR.comments = input.reopenReason;
data.success = supTaskGR.update();
}
- Client controller:
The c.completeTask OOB function must be updated in order to include the new action type:
if (c.data.task.task_type === 'case_resolution') {
c.data.actionType = 'case_resolution';
}
As well as a new function in order to execute the expected actions when the requestor clicks on 'Re-open' case:
c.reopenCase = function(tableName, sysId, res) {
var reopenReason = document.getElementById("reopen-case-reason").value;
if(reopenReason == ""){
// alert(i18n.getMessage("Please, provide reason for re-opening the Case"));
alert("Please, provide reason for re-opening the Case");
} else {
c.data.reopenReason = reopenReason;
c.data.action = "reopenCase";
c.data.tableName = tableName;
c.data.sysId = sysId;
c.data.res = res;
c.server.update();
}
};
Use the new widget in the Supplier Portal
Finally, it must be ensured that Supplier contacts can use the new widget created from the Supplier Collaboration Portal, so that they can use the feature as expected. To do it, navigate to 'Employee Center > Administration > To-dos Configuration'. Once the list opens, select the 'Supplier Task' record, and navigate to the 'Related lists' section of it. Open the only record that should be available under 'To-dos Widget Mappings' tab, and replace the OOB 'Supplier Task To-do' widget, with the new one created in the previous step:
Additional Notes
1. In order to implement this feature, it will be required to modify the system in different Scopes, depending on which object we are updating, and thus developers should be changing their scope to the right one to make sure the implementation succeeds.
2. Not all the case types are necessarily entitled to be good candidates for this feature. Sometimes, the resolution of a case might not require the requestor's confirmation. A good example of this would be Supplier onboarding, in which the requestor might not be required to confirm the solution, as the outcome is simply to have them onboarded into the system. A good candidate for this feature would be for example 'General inquiry' case types. So, it is recommended to correctly assess which case types should use this feature depending on details, and exclude the ones that are not needed, by modifying the conditions in the UI Actions and any other relevant place.
3. In some ServiceNow versions, the 'Awaiting information' state might not be available in Supplier case, and therefore it should be excluded from the 'Condition' field in the new 'Resolve case' UI Action created.
4. It has been noticed that in some ServiceNow versions, the 'createSupplierTask' function used in the 'Resolve case' UI Action does not calculate the 'Due date' for the task automatically based on the Decision table created for that, and therefore the system generates an error message when clicking on it. In order to solve it, the 'SupplierCommonUtil' Script Include must be modified to overwrite that function from its original OOB Script Include (SupplierCommonUtilSNC). If no other function must be overwritten for that Script Include, the new version would look like this:
var SupplierCommonUtil = Class.create();
SupplierCommonUtil.prototype = Object.extendsObject(sn_slm.SupplierCommonUtilSNC, {
initialize: function() {},
createSupplierTask: function(supplierTaskObj, isCreationFromCI) {
try {
if (isCreationFromCI === undefined) {
isCreationFromCI = true; // default value
}
if (isCreationFromCI) {
return this.createSupplierTaskFromCatalogItem(supplierTaskObj);
} else {
var supplierTaskGr = new GlideRecord('sn_slm_task');
supplierTaskGr.initialize();
supplierTaskGr.setValue('assigned_to', supplierTaskObj.assigned_to);
supplierTaskGr.setValue('parent', supplierTaskObj.parent);
supplierTaskGr.setValue('action_type_for_task', supplierTaskObj.action_type_for_task);
supplierTaskGr.setValue('catalog_item', supplierTaskObj.catalog_item);
supplierTaskGr.setValue('state', supplierTaskObj.state);
supplierTaskGr.setValue('opened_by', supplierTaskObj.opened_by);
supplierTaskGr.setValue('supplier', supplierTaskObj.supplier);
supplierTaskGr.setValue('document_reference', supplierTaskObj.document_reference);
if (!gs.nil(supplierTaskObj.description)) {
supplierTaskGr.setValue('description', supplierTaskObj.description);
}
if (!gs.nil(supplierTaskObj.short_description)) {
supplierTaskGr.setValue('short_description', supplierTaskObj.short_description);
}
if (!gs.nil(supplierTaskObj.task_audience)) {
supplierTaskGr.setValue('task_audience', supplierTaskObj.task_audience);
}
// FIX for Due date being mandatory
supplierTaskGr.setValue('due_date', this.getDefaultDueDate(supplierTaskObj.action_type_for_task,this.SUPPLIER_TASK_DEFAULT_DUE_DATE_DECISION_TABLE));
var result = supplierTaskGr.insert();
return result;
}
} catch (error) {
throw error;
}
},
type: 'SupplierCommonUtil'
});
where we can see how the function calculates the due date by using another existing function within the same Script Include.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @Javier Dom_nech :
Thank you for identifying this gap and suggesting a practical workaround.
That said, my broader question is: Why can’t this be an out-of-the-box (OOTB) solution across S2P, SLO, and potentially APO—especially in Case Management?
The functionality already exists in HRSD. We simply need to replicate it across these modules. Specifically, HRSD’s Case Management leverages a robust state model along with UI Actions like “Start Work”, “Suspend”, etc., all integrated within the Agent Workspace.
We’ve already raised this gap with our ServiceNow account partner and are hopeful that improvements will be considered in next 1 or 2 upcoming releases.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @Bhavesh Bijagar,
Unfortunately, I do not have enough information to answer your question with a lot of details.
Here in ServiceNow, we listen to our customers and their necessities, and try to include new features in every Release to satisfy them. However, specific priorities are determined but Product Teams, so depending on what they have in the roadmap, availability, capacity, feasiblity, general interest, etc. they can implement some capabilities or others for each version.
I am not sure if this one will be soon released OOTB, and that's why I created this article. Because we heard from some customers that it might be interesting for them, and implemented it for a couple of them. So, sharing the knowledge with the community in case somebody else is interested in implementing it, and can't wait until it is released OOB if it eventually does.