Name
global.ProcSourceRequestManager
Description
Manages Source Request.
Script
var ProcSourceRequestManager = Class.create();
ProcSourceRequestManager.C_STOCK_ORDER_SYS_ID = '4109aa5fdb22001015a8ffefbf961984';
ProcSourceRequestManager.prototype = {
initialize: function(request) {
this.request = request;
this.isSAMEnabled = GlidePluginManager.isActive('com.snc.software_asset_management');
this.isSAMPActive = GlidePluginManager.isActive('com.snc.samp');
this.isSAMSActive = GlidePluginManager.isActive('com.snc.sams');
this.isHAMPActive = GlidePluginManager.isActive('com.sn_hamp');
this.isEAMActive = GlidePluginManager.isActive('com.sn_eam');
this.isPhyAssetActive = GlidePluginManager.isActive('com.sn_phy_assets');
this.isServiceLocationActive = this.isPhyAssetActive && (new TableUtils('sn_itam_common_m2m_stockroom_location').tableExists())
&& sn_itam_common.InventoryUtil && sn_itam_common.InventoryUtil.prototype._getStockroomsServicingLocation;
this.isDistributionChannelActive = this.isPhyAssetActive && (new TableUtils('sn_itam_common_m2m_stockroom_channel').tableExists());
this.errorsInRequest = 0;
// Order combinations Arrays
this.LOTOPO_ARR = ['local', 'transfer', 'purchase'];
this.LOTO_ARR = ['local', 'transfer'];
this.TOPO_ARR = ['transfer', 'purchase'];
this.tablePropertyMap = {};
this.tablePropertyMap['sys_user'] = {
property: 'com.snc.procurement.sourcing.sys_user.searchField',
defaultValue: 'name'
};
this.tablePropertyMap['alm_stockroom'] = {
property: 'com.snc.procurement.sourcing.alm_stockroom.searchField',
defaultValue: 'name'
};
this.tablePropertyMap['cmdb_ci'] = {
property: 'com.snc.procurement.sourcing.cmdb_ci.searchField',
defaultValue: 'name'
};
this.tablePropertyMap['samp_sw_metric_group'] = {
property: 'com.snc.procurement.sourcing.samp_sw_metric_group.searchField',
defaultValue: 'name'
};
this.allowLocalStockroomInTO = false;
if (gs.getProperty('glide.asset.procurement.sourcing.local_stock_transfer') === 'true') {
this.allowLocalStockroomInTO = true;
}
},
_isSAMEnabled: function() {
return this.isSAMEnabled == 'true' || this.isSAMEnabled == true;
},
getAllStockRoom: function() {
var stockrooms = this._getRecordObject('alm_stockroom',
[],
['sys_id', 'name', 'quantity']);
return (new JSON()).encode(stockrooms);
},
getVendorsForModelForWorkspace: function(modelId) {
return this._getVendors(modelId);
},
getRequestItemsForWorkspace: function(scReqSysid, scReqTaskSysid) {
var reqItems = JSON.parse(this.getRequestItemsInternal(scReqSysid, scReqTaskSysid));
var request = {};
var procSourceRequestManager = new global.ProcSourceRequestManager();
reqItems.forEach(function(reqItem) {
var gr = new GlideRecord('sys_attachment');
gr.addQuery('table_name', 'ZZ_YY' + reqItem.cat_item.sys_class_name);
gr.addQuery('file_name', 'picture');
gr.addQuery('table_sys_id', reqItem.cat_item.sys_id);
gr.query();
if (gr.hasNext()) {
gr.next();
reqItem.cat_item.picture = gr.getValue('sys_id') + '.iix';
}
if(procSourceRequestManager.isDistributionChannelActive && sn_itam_common.InventoryUtil.getDistributionChannelUserPreference() === 'true') {
//This is the check for HAM/EAM stock order request, where excludeStockroom is the destination stockroom and is not empty
var excludeStockroom;
if((GlidePluginManager.isActive('com.sn_hamp') && sn_hamp.StockOrderUtils.isStockOrderItem(reqItem.cat_item.sys_id))
|| (GlidePluginManager.isActive('com.sn_eam') && sn_eam.StockOrderUtils.isStockOrderItem(reqItem.cat_item.sys_id))) {
excludeStockroom = reqItem.dest_stockroom.value;
}
var transferTotal = sn_itam_common.InventoryUtil.getTotalTransferInstockForDistributionChannel(reqItem.cat_item.model, reqItem.requested_user.location, excludeStockroom);
reqItem['transfer_instock'] = reqItem['local_instock'] + transferTotal;
if (!procSourceRequestManager.allowLocalStockroomInTO) {
reqItem['transfer_instock'] = transferTotal;
}
var userLocationStockrooms = sn_itam_common.InventoryUtil.getStockroomsBasedOnLocation(reqItem.requested_user.location.sys_id);
var userLocationServicingStockrooms = sn_itam_common.InventoryUtil.getDestinationStockroomsServicingUserLocation(reqItem.requested_user.location.sys_id, userLocationStockrooms);
reqItem.defaultServicableStockrooms = userLocationServicingStockrooms;
}
});
reqItems = this.transformToWSCompatibleInput(reqItems);
request.request_items = reqItems;
var pluginsStatus = {
'isSAMEnabled' : this.isSAMEnabled,
'isSAMPEnabled' : this.isSAMPActive,
'isDistributionChannelActive' : this.isDistributionChannelActive
};
//To set state variable to be used for user prefernces in Distribution Channel
if(this.isDistributionChannelActive && sn_itam_common.InventoryUtil.getDistributionChannelUserPreference() === 'true') {
request.considerDistributionChannel = true;
}
else {
request.considerDistributionChannel = false;
}
var messages = {
'CANNOT_ASSIGN_MORE_THAN_AVAILABLE_RIGHTS': gs.getMessage('Cannot assign more than available rights'),
'DUPLICATE_ENTITLEMENT': gs.getMessage('Duplicate entitlement'),
'PROVIDE_QUANTITY_MORE_THAN_ZERO': gs.getMessage('Provide quantity more than zero'),
'REQUEST_ITEMS_SOURCED': gs.getMessage('Congratulations! All assets for this request have been successfully sourced. Please refer to the request record for more information.'),
'RIGHTS_CANNOT_BE_MORE_THAN_AVAILABLE': gs.getMessage('Rights cannot be more than available'),
'SELECT_DESTINATION_STOCKROOM': gs.getMessage('Select destination stockroom'),
'SELECT_DEVICE_TO_COMPLETE_ALLOCATION': gs.getMessage('Select the device to complete device allocation'),
'SELECT_DEVICE_TO_COMPLETE_ASSIGNMENT': gs.getMessage('Select the device to complete device assignment'),
'SELECT_ENTITLEMENT': gs.getMessage('Select entitlement'),
'SELECT_LICENSE': gs.getMessage('Select license'),
'SELECT_LICENSE_METRIC': gs.getMessage('Select license metric'),
'SELECT_METRIC_GROUP': gs.getMessage('Select metric group'),
'SELECT_RESERVED_FOR': gs.getMessage('Select reserved for'),
'SELECT_SOURCE_STOCKROOM': gs.getMessage('Select source stockroom'),
'SELECT_TYPE': gs.getMessage('Select type'),
'SELECT_USER_TO_COMPLETE_ALLOCATION': gs.getMessage('Select the user to complete user allocation'),
'SELECT_USER_TO_COMPLETE_ASSIGNMENT': gs.getMessage('Select the user to complete user assignment'),
'SELECT_VENDOR': gs.getMessage('Select vendor'),
'SOURCE_QUANITY_MORE_THAN_INSTOCK': gs.getMessage('Source quantity cannot be more than instock'),
'SOURCED_RIGHTS_EXCEED_AVAILABLE_RIGHTS': gs.getMessage('Sourced rights across requests for an item cannot exceed the available rights'),
'TOTAL_QUANTITY_SOURCE_STOCKROOM_EXCEED_INSTOCK': gs.getMessage('Total source quantity of all orders for selected source stockroom exceeded in-stock quantity'),
'TOTAL_QUANTITY_EXCEED_TO_BE_SOURCED_QUANTITY': gs.getMessage('Total quantity of all orders for selected request item exceeds the quantity to be sourced'),
'TOTAL_RIGHTS_EXCEED_AVAILABLE_RIGHTS': gs.getMessage('Total rights of all assignments for selected license exceeded available rights'),
'UNABLE_TO_COMPLETE_OPERATION': gs.getMessage('Unable to complete operation, review errors below'),
// Messages for button tooltips
'localstock_TOOLTIP': gs.getMessage('Click this button to create stock order'),
'transfer_TOOLTIP': gs.getMessage('Click this button to create transfer order'),
'sampurchase_TOOLTIP': gs.getMessage('Click this button to create purchase order'),
'purchase_TOOLTIP': gs.getMessage('Click this button to create purchase order'),
'allocation_TOOLTIP': gs.getMessage('Click this button to create allocation'),
'samassignment_TOOLTIP': gs.getMessage('Click this button to create assignment'),
'assignment_TOOLTIP': gs.getMessage('Click this button to create assignment'),
};
request.pluginsStatus = pluginsStatus;
request.messages = messages;
return JSON.stringify(request);
},
transformToWSCompatibleInput: function(reqItems) {
var rItemsForWs = [];
reqItems.forEach(function(ritm) {
var showCard = ritm.showCard;
var cards = [];
if (ritm.item_model_type != 'software') {
if (showCard.local) {
cards.push({
cardLabel: gs.getMessage('Local stock'),
cardValue: ritm.local_instock,
buttonLabel: gs.getMessage('Consume'),
selectable: ritm.local_instock > 0,
buttonClickValue: 'localstock'
});
}
if (showCard.transfer) {
cards.push({
cardLabel: gs.getMessage('Transferable stock'),
cardValue: ritm.transfer_instock,
buttonLabel: gs.getMessage('Transfer'),
selectable: ritm.transfer_instock > 0,
buttonClickValue: 'transfer'
});
}
if (showCard.purchase) {
cards.push({
cardLabel: gs.getMessage('Vendor purchase'),
cardValue: ritm.remain_quantity,
buttonLabel: gs.getMessage('Purchase'),
selectable: ritm.hasVendors,
buttonClickValue: 'purchase'
});
}
} else {
var hasTotalRights = false;
if (ritm.total_rights > 0) {
hasTotalRights = true;
}
if (this.isSAMPActive) {
cards.push({
cardLabel: gs.getMessage('Available rights'),
cardValue: ritm.total_rights,
buttonLabel: gs.getMessage('Allocate'),
selectable: hasTotalRights,
buttonClickValue: 'allocation'
});
}
else {
if (this.isSAMEnabled){
cards.push({
cardLabel: gs.getMessage('Available rights'),
cardValue: ritm.total_rights,
buttonLabel: gs.getMessage('Assign'),
selectable: hasTotalRights,
buttonClickValue: 'samassignment'
});
} else {
cards.push({
cardLabel: gs.getMessage('Available rights'),
cardValue: ritm.total_rights,
buttonLabel: gs.getMessage('Assign'),
selectable: hasTotalRights,
buttonClickValue: 'assignment'
});
}
}
if (showCard.purchase) {
if (this.isSAMSActive) {
cards.push({
cardLabel: gs.getMessage('Vendor purchase'),
cardValue: ritm.remain_quantity,
buttonLabel: gs.getMessage('Purchase'),
selectable: ritm.hasVendors,
buttonClickValue: 'sampurchase'
});
} else {
cards.push({
cardLabel: gs.getMessage('Vendor purchase'),
cardValue: ritm.remain_quantity,
buttonLabel: gs.getMessage('Purchase'),
selectable: ritm.hasVendors,
buttonClickValue: 'purchase'
});
}
}
}
ritm.cards = cards;
}, this);
return reqItems;
},
getRequestItemsInternal: function(scReqSysid, scReqTaskSysid) {
var reqItems = this._getRequestData(scReqSysid, scReqTaskSysid);
//add support for EAM Items
var EAMreqItems = [];
if (this.isEAMActive && sn_eam.EAMProcSourceRequestManager &&
sn_eam.EAMProcSourceRequestManager.prototype._EAMgetRequestData) {
var eamProcSourceRequestManager = new sn_eam.EAMProcSourceRequestManager();
EAMreqItems = eamProcSourceRequestManager._EAMgetRequestData(scReqSysid);
reqItems = reqItems.concat(EAMreqItems);
if (reqItems.length > 0) {
return JSON.stringify(reqItems);
}
}
var HAMreqItems = [];
if (this.isHAMPActive && sn_hamp.HAMProcSourceRequestManager &&
sn_hamp.HAMProcSourceRequestManager.prototype._HAMgetRequestData) {
var hamProcSourceRequestManager = new sn_hamp.HAMProcSourceRequestManager();
HAMreqItems = hamProcSourceRequestManager._HAMgetRequestData(scReqSysid);
reqItems = reqItems.concat(HAMreqItems);
}
return JSON.stringify(reqItems);
},
getSCRequestItems: function() {
var scReqSysid = this.request.getParameter('sysparm_scReq');
var scReqTaskSysid = this.request.getParameter('sysparm_scReqTask');
return this.getRequestItemsInternal(scReqSysid, scReqTaskSysid);
},
_getRequestData: function(scReqSysid, scReqTaskSysid) {
var reqItems = this._getRecordObject('sc_req_item',
[{
key: 'request',
value: scReqSysid
},
{
key: 'sourced',
value: 'false'
},
[{
key: 'cat_item.model',
value: 'null',
operator: '!='
}]
],
['sys_id', 'number', 'quantity', 'quantity_sourced', 'request', 'price', 'state', 'received', 'sourced', 'requested_for'], {
'cat_item': {
table: 'sc_cat_item',
fields: ['sys_class_name', 'cost', 'sys_id', 'model', 'name', 'category']
},
'request': {
table: 'sc_request',
fields: ['sys_id', 'requested_for']
}
});
for (var i = 0; i < reqItems.length; i++) {
var item = reqItems[i];
this._setInitialUIProperties(item);
item['remain_quantity'] = parseInt(item.quantity) - parseInt(item.quantity_sourced);
item.cat_item.displayName = item.cat_item.name;
this._populateUserInfo(item);
if (item.cat_item.model) {
if (this.isEAMActive){
var modelGr = new GlideRecord(global.AssetManagementConstants.MODEL_CLASSES.PRODUCT_MODEL);
modelGr.get(item.cat_item.model);
if(modelGr.ref_sn_ent_model.model_type == sn_eam.EAMConstants.MODEL_TYPE.USERASSEMBLED){
item.showCard.purchase = false;
}
}
this._getSourceableData(item, '');
}
if (item.showCard.local &&
this._getLocation(item)) {
this._populateLocalOrderInfo(item);
}
}
return reqItems;
},
_populateUserInfo: function(item) {
var requestedFor = item.requested_for || item.request.requested_for;
item.requested_user = {};
if (!gs.nil(requestedFor)) {
var userColumns = ['sys_id', 'name', 'location'];
userColumns.push(item.userSearchField);
var userInfo = this._getRecordObject('sys_user',
[{
key: 'sys_id',
value: requestedFor
}],
userColumns,{
'location':{
table:'cmn_location',
fields:['name']
}
});
item.requested_user = userInfo.length === 1 ? userInfo[0] : {};
}
return item;
},
_getSourceableData: function(item, excludeStockroom) {
item['item_model_type'] = this._getItemModelType(item.cat_item.model);
/* Get aggregated count to enable/disable Add TO/PO/ASGN actions */
item['hasVendors'] = (new AssetUtils()).hasVendors(item.cat_item.model);
if (item.item_model_type == 'software') {
if (this.isSAMPActive) {
item.total_rights = this._getAvailableRightsInSAMP(item.cat_item.model);
} else if (this._isSAMEnabled() && this._isCounterRan(this.request.getParameter('sysparm_model'))) {
item.total_rights = (new SoftwareItemProcessor()).getValuation(item.cat_item.model);
} else {
item.total_rights = this._getAvailableRights(item.cat_item.model);
}
} else {
item['total_instock'] = this._getTotalInstockForModel(item.cat_item.model, excludeStockroom);
item['local_instock'] = this._getLocalInstockForModel(item, excludeStockroom);
item['transfer_instock'] = item['total_instock'];
if (!this.allowLocalStockroomInTO) {
item['transfer_instock'] -= item['local_instock'];
}
}
return item;
},
_populateLocalOrderInfo: function(item) {
var defaultUser = {};
defaultUser.displayValue = item.requested_user[item.userSearchField];
defaultUser.value = item.requested_user.sys_id;
item.userDefault.local = JSON.stringify(defaultUser);
var assetGr = this._getAssetForLocalDefaultStockroom(item.cat_item.model, item.sourceExclude.local, this._getLocation(item));
if (!gs.nil(assetGr)) {
var sourceStockroom = {};
sourceStockroom['name'] = assetGr.stockroom.name + '';
sourceStockroom['sys_id'] = assetGr.stockroom + '';
sourceStockroom['instock'] = assetGr.getAggregate('SUM', 'quantity');
// Auto-populate Source Stockroom for Local Order
item.sourceDefault.local = JSON.stringify(sourceStockroom);
}
// Auto-populate Destination Stockroom for Transfer Order
var destStockroom = this._findInDestStockroomList(item.destQualifier.transfer, this._getLocation(item), item.stockroomSearchField);
if (!gs.nil(destStockroom)) {
item.destDefault.transfer = destStockroom;
}
// Auto-populate Destination Stockroom for Purchase Order
if (!gs.nil(destStockroom) && item.destQualifier.transfer === item.destQualifier.purchase) {
item.destDefault.purchase = destStockroom;
} else {
destStockroom = this._findInDestStockroomList(item.destQualifier.purchase, this._getLocation(item), item.stockroomSearchField);
if (!gs.nil(destStockroom)) {
item.destDefault.purchase = destStockroom;
}
}
return item;
},
_setInitialUIProperties: function(item) {
// All UI cards should be visible by default
item.showCard = this._setObjectDefaultValue(true, this.LOTOPO_ARR);
// Source stockroom and Vendor should be editable by default
item.sourceReadOnly = this._setObjectDefaultValue(false, this.LOTO_ARR);
item.vendorReadOnly = this._setObjectDefaultValue(false, ['purchase']);
// Input for source stockroom is Object/JSON
item.sourceDefault = this._setObjectDefaultValue(JSON.stringify({}), this.LOTO_ARR);
// All stockrooms shouild be available for sourcing
item.sourceExclude = this._setObjectDefaultValue('', this.LOTO_ARR);
// User and destination stockroom should be editable by default
item.userReadOnly = this._setObjectDefaultValue(false, ['local']);
item.destReadOnly = this._setObjectDefaultValue(false, this.TOPO_ARR);
// Input for user and destination stockroom is Object/JSON
item.userDefault = this._setObjectDefaultValue(JSON.stringify({}), ['local']);
item.destDefault = this._setObjectDefaultValue(JSON.stringify({}), this.TOPO_ARR);
// Only avtive users should be selected
item.userQualifier = this._setObjectDefaultValue('active=true', ['local']);
// Any stockroom can be selected as destination by default
item.destQualifier = this._setObjectDefaultValue('', this.TOPO_ARR);
// Default search field for stockroom is 'name'
item.stockroomSearchField = this._getSerachField('alm_stockroom');
// Default search field for user is 'name'
item.userSearchField = this._getSerachField('sys_user');
// Default search field for device is 'name'
item.deviceSearchField = this._getSerachField('cmdb_ci');
// Default search field for metric_group is 'name'
item.metricGroupSearchField = this._getSerachField('samp_sw_metric_group');
},
_getSerachField: function(table) {
var propertyValue = AssetUtils.getAssetProperty(this.tablePropertyMap[table].property, this.tablePropertyMap[table].defaultValue);
var gr = new GlideRecord(table);
if (gr.isValidField(propertyValue)) {
return propertyValue;
} else {
return this.tablePropertyMap[table].defaultValue;
}
},
_setObjectDefaultValue: function(defaultValue, keys, obj) {
var variableObj = obj || {};
keys.forEach(function(key) {
variableObj[key] = defaultValue;
});
return variableObj;
},
_getAvailableRights: function(model, license) {
var totalLicenses = 0;
var allocatedLicenses = 0;
var availableLicenses = 0;
var licenseGr = new GlideAggregate('alm_license');
licenseGr.addQuery('model', model);
licenseGr.addQuery("install_status", "1"); /* Only consider in-use license */
if (license)
licenseGr.addQuery('sys_id', license);
licenseGr.addAggregate('SUM', 'rights');
licenseGr.groupBy('model');
licenseGr.query();
if (licenseGr.next()) {
totalLicenses = licenseGr.getAggregate('SUM', 'rights');
}
var entitlementGr = new GlideAggregate('alm_entitlement');
entitlementGr.addQuery('licensed_by.model', model);
entitlementGr.addQuery("licensed_by.install_status", "1"); /* Only consider in-use license */
if (license)
entitlementGr.addQuery('licensed_by', license);
entitlementGr.addAggregate('COUNT');
entitlementGr.query();
if (entitlementGr.next()) {
allocatedLicenses = entitlementGr.getAggregate('COUNT');
}
return (totalLicenses - allocatedLicenses);
},
_getAvailableRightsInSAMP: function(swModel) {
var rightsGr = new GlideAggregate('alm_license');
rightsGr.addQuery('model', swModel);
rightsGr.addQuery('install_status', '1'); // Consider only In use license
rightsGr.addQuery('product_type', '!=', 'maintenance'); // Exclude maintenance entitlements
rightsGr.addAggregate('SUM', 'allocations_available');
rightsGr.setGroup(false);
rightsGr.query();
rightsGr.next();
return Number(rightsGr.getAggregate('SUM', 'allocations_available'));
},
/* Decide type of item (software/hardware) based on requested item's model*/
_getItemModelType: function(model) {
var type = '';
if (model) {
var modelGr = new GlideRecord('cmdb_model');
modelGr.get(model);
if (modelGr.instanceOf('cmdb_hardware_product_model')) {
type = 'hardware';
} else if (modelGr.instanceOf('cmdb_software_product_model')) {
type = 'software';
}
}
return type;
},
getSourceStockRoomForItem: function() {
var model = this.request.getParameter('sysparm_model');
var stockrooms = [];
var gr2 = new GlideAggregate("alm_asset");
global.AssetUtils.addAssetQuery(gr2, global.AssetUtils.ASSET_FUNCTION_FEATURE.SOURCING);
if (model)
gr2.addQuery("model", model);
gr2.addQuery("install_status", "6");
gr2.addQuery("substatus", "available");
gr2.groupBy("stockroom");
gr2.query();
while (gr2.next()) {
var stockroom = {};
stockroom.name = gr2.stockroom.name + '';
stockroom.sys_id = gr2.stockroom.sys_id + '';
stockrooms.push(stockroom);
}
return (new JSON()).encode(stockrooms);
},
_getTotalInstockForModel: function(model, excludeStockroom) {
var gr = new GlideAggregate('alm_asset');
var counter = 0;
global.AssetUtils.addAssetQuery(gr, global.AssetUtils.ASSET_FUNCTION_FEATURE.SOURCING);
gr.addQuery('model', model);
gr.addQuery('install_status', global.AssetUtils.INSTOCK_STATUS);
gr.addQuery('substatus', global.AssetUtils.AVAILABLE_SUBSTATUS);
//Stock order exclude stock in requested stockroom
if (!gs.nil(excludeStockroom))
gr.addQuery('stockroom', 'NOT IN', excludeStockroom);
gr.addAggregate('SUM', 'quantity');
gr.groupBy('model');
gr.query();
if (gr.next()) {
counter = parseInt(gr.getAggregate('SUM', 'quantity'));
}
return counter;
},
/*
* Returns array of Location SysIds
* Contains the requested user's location and all its parents
*/
_getAllParentLocations: function(userLocation) {
var gr = GlideRecord('cmn_location');
var parentLocations = [];
var locId = userLocation;
while(locId) {
gr.get(locId);
if(gr.isValidRecord()) {
parentLocations.push(gr.sys_id.toString());
locId = gr.parent;
} else {
break;
}
}
return parentLocations;
},
/*
* Returns array of Stockroom SysIds
* Contains all the stockrooms that support given user location
* Support is defined in sn_itam_common_m2m_stockroom_location table
* Excludes all the Stockrooms that have active=false for
* the location or any of its parents.
*/
_getStockroomsServicingLocation: function(userLocation) {
var parentLocations = this._getAllParentLocations(userLocation);
//Get all stockrooms that have any of the parent locations supported
var stockroomGr = new GlideAggregate("sn_itam_common_m2m_stockroom_location");
stockroomGr.addQuery('location', 'IN', parentLocations);
stockroomGr.addQuery('active', true);
stockroomGr.groupBy('stockroom');
stockroomGr.query();
var stockroomsServingLoc = [];
while(stockroomGr.next()) {
stockroomsServingLoc.push(stockroomGr.getValue("stockroom"));
}
//Remove all those stockrooms where any of the parent location is active false
stockroomGr.initialize();
stockroomGr.addQuery('location', 'IN', parentLocations);
stockroomGr.addQuery('active', false);
stockroomGr.groupBy('stockroom');
stockroomGr.query();
while(stockroomGr.next()) {
var index = stockroomsServingLoc.indexOf(stockroomGr.getValue("stockroom"));
if (index > -1) {
stockroomsServingLoc.splice(index, 1);
}
}
return stockroomsServingLoc;
},
/*
* Returns count of available assets of a model
* present in stockrooms of requested user's location.
*
* Returns 0, if it is stock order or
*requested user's location is empty.
*/
_getLocalInstockForModel: function(item, excludeStockroom) {
if (!item.showCard.local ||
!this._getLocation(item)) {
return 0;
}
var count = 0;
var gr = new GlideAggregate('alm_asset');
global.AssetUtils.addAssetQuery(gr, global.AssetUtils.ASSET_FUNCTION_FEATURE.SOURCING);
gr.addQuery('model', item.cat_item.model);
gr.addQuery('install_status', global.AssetUtils.INSTOCK_STATUS);
gr.addQuery('substatus', global.AssetUtils.AVAILABLE_SUBSTATUS);
if (!gs.nil(excludeStockroom))
gr.addQuery('stockroom', 'NOT IN', excludeStockroom);
var stockroomQc = gr.addQuery('stockroom.location', this._getLocation(item));
if(this.isServiceLocationActive) {
//Consider all the stockrooms for Consume Local that service user's location
var inventoryUtil = new sn_itam_common.InventoryUtil();
var stockroomsServingLoc = inventoryUtil._getStockroomsServicingLocation(this._getLocation(item));
if (!gs.nil(stockroomsServingLoc))
stockroomQc.addOrCondition('stockroom', 'IN', stockroomsServingLoc);
}
gr.addAggregate('SUM', 'quantity');
gr.groupBy('model');
gr.setOrder(false);
gr.query();
if (gr.next()) {
count = parseInt(gr.getAggregate('SUM', 'quantity'));
}
return count;
},
_findInDestStockroomList: function(qualifier, location, displayColumn) {
var destStockroom = {};
var gr = new GlideRecord('alm_stockroom');
if (!gs.nil(qualifier)) {
gr.addEncodedQuery(qualifier);
}
gr.addQuery('location', location);
gr.setLimit(2);
gr.query();
while (gr.next()) {
if (!gr.hasNext()) {
destStockroom['value'] = gr.getValue('sys_id');
destStockroom['displayValue'] = gr.getDisplayValue(displayColumn);
return JSON.stringify(destStockroom);
}
break;
}
return '';
},
_addSourceStockroomConditions: function(gr, model, excludeStockroom, userLocation, orderType, distributionChannel) {
global.AssetUtils.addAssetQuery(gr, global.AssetUtils.ASSET_FUNCTION_FEATURE.SOURCING);
gr.addQuery('model', model);
gr.addQuery('install_status', '6');
gr.addQuery('substatus', 'available');
if(orderType === 'transfer_order' && this.isDistributionChannelActive && !gs.nil(distributionChannel) && distributionChannel.length > 0) {
gr.addQuery('stockroom', 'IN', distributionChannel);
}
if (!gs.nil(userLocation)) {
if ('local_order' === String(orderType)) {
var stockroomQc = gr.addQuery('stockroom.location', 'IN', userLocation);
if(this.isServiceLocationActive) {
//Consider all stockrooms for Consume Local that service user's location
var inventoryUtil = new sn_itam_common.InventoryUtil();
var stockroomsServingLoc = inventoryUtil._getStockroomsServicingLocation(userLocation);
if (!gs.nil(stockroomsServingLoc))
stockroomQc.addOrCondition('stockroom', 'IN', stockroomsServingLoc);
}
} else {
if (!this.allowLocalStockroomInTO) {
gr.addQuery('stockroom.location', 'NOT IN', userLocation);
//For HAM/EAM stock order flow - excludeStockroom is destination stockroom which is fixed
if(this.isServiceLocationActive && (gs.nil(excludeStockroom) || String(excludeStockroom) === '')) {
//Exclude all stockrooms that service user's location from TO
//since they will be cosidered for Consume local
var inventoryUtils = new sn_itam_common.InventoryUtil();
var excludeSRs = inventoryUtils._getStockroomsServicingLocation(userLocation);
if (!gs.nil(excludeSRs))
gr.addQuery('stockroom', 'NOT IN', excludeSRs);
}
}
}
}
if (!gs.nil(excludeStockroom))
gr.addQuery('stockroom', 'NOT IN', excludeStockroom);
gr.addAggregate('SUM', 'quantity');
gr.groupBy('stockroom');
},
_getAssetForLocalDefaultStockroom: function(model, excludeStockroom, userLocation) {
var counter = 0;
var gr = new GlideAggregate('alm_asset');
this._addSourceStockroomConditions(gr, model, excludeStockroom, userLocation, 'local_order');
gr.setLimit(2);
gr.query();
while (gr.next()) {
if (!gr.hasNext()) {
return gr;
}
break;
}
return '';
},
_getSourceStockroomWithQuantityForItem: function(model, excludeStockroom, userLocation, orderType, distributionChannelFlag) {
var stockrooms = [];
var considerDistributionChannel = this.isDistributionChannelActive && !gs.nil(distributionChannelFlag) && distributionChannelFlag;
var distributionChannel = [];
var channelStockroomsWithRank = {};
if(considerDistributionChannel && orderType === 'transfer_order') {
//To include channel of only excluded stockroom which is the destination for HAM/EAM stock order flow
if(!gs.nil(excludeStockroom)) {
channelStockroomsWithRank = sn_itam_common.InventoryUtil.getStockroomsServicingBaseStockroom(excludeStockroom);
distributionChannel = Object.keys(channelStockroomsWithRank);
if(distributionChannel.length === 0) {
return stockrooms;
}
}
else {
if(!gs.nil(userLocation)) {
var userLocationStockrooms = sn_itam_common.InventoryUtil.getStockroomsBasedOnLocation(userLocation);
if(!gs.nil(userLocationStockrooms) && userLocationStockrooms.length > 0) {
channelStockroomsWithRank = sn_itam_common.InventoryUtil.getStockroomsServicingBaseStockroom(userLocationStockrooms[0]);
distributionChannel = Object.keys(channelStockroomsWithRank);
} else {
var stockroomsServingLoc = new sn_itam_common.InventoryUtil()._getStockroomsServicingLocation(userLocation);
if(stockroomsServingLoc.length > 0) {
channelStockroomsWithRank = sn_itam_common.InventoryUtil.getStockroomsServicingLocationCoverageStockrooms(stockroomsServingLoc);
distributionChannel = Object.keys(channelStockroomsWithRank);
}
}
if(distributionChannel.length === 0) {
return stockrooms;
}
}
}
}
var counter = 0;
var gr = new GlideAggregate('alm_asset');
this._addSourceStockroomConditions(gr, model, excludeStockroom, userLocation, orderType, distributionChannel);
gr.query();
while (gr.next()) {
var stockroom = {};
stockroom['name'] = gr.stockroom.name + '';
stockroom['sys_id'] = gr.stockroom + '';
counter = gr.getAggregate('SUM', 'quantity');
stockroom['instock'] = counter;
if(considerDistributionChannel) {
stockroom['rank'] = channelStockroomsWithRank[gr.stockroom.toString()];
}
stockrooms.push(stockroom);
}
if(considerDistributionChannel) {
stockrooms.sort(function (x, y) {
return x.rank - y.rank;
});
}
return stockrooms;
},
getSourceStockroomWithQuantityForItemForWorkspace: function(ritmId, modelId, excludeStockroom, userLocation, orderType, distributionChannelFlag) {
var stockrooms = [];
if (modelId) {
stockrooms = this._getSourceStockroomWithQuantityForItem(modelId, excludeStockroom, userLocation, orderType, distributionChannelFlag);
}
return stockrooms;
},
getSourceStockroomWithQuantityForItem: function() {
var itemSysid = this.request.getParameter('sysparm_itemsysid');
var modelSid = this.request.getParameter('sysparm_model');
var excludeStockroom = this.request.getParameter('sysparm_excludeStockroom');
var userLocation = this.request.getParameter('sysparm_userLocation');
var orderType = this.request.getParameter('sysparm_orderType');
var stockrooms = [];
if (modelSid) {
stockrooms = this._getSourceStockroomWithQuantityForItem(modelSid, excludeStockroom, userLocation, orderType);
}
return (new JSON()).encode(stockrooms);
},
getAvailableQuantity: function() {
var data = {};
var stockroom = this.request.getParameter('sysparm_stockroom');
var model = this.request.getParameter('sysparm_model');
data['quantity'] = (new AssetUtils()).getAvailableQuantity(model, stockroom);
return (new JSON()).encode(data);
},
_getVendors: function(model) {
var data = [];
var vendorsStr = (new AssetUtils()).getVendors(model);
if (vendorsStr) {
var vendors = vendorsStr.split('^');
var i = 1;
while (i < vendors.length) {
var vendor = {};
vendor['name'] = vendors[i];
/* Extract name and cost */
var matches = vendors[i].match(/(.*)\((.*)\)/);
if (matches.length > 2) {
vendor['display_name'] = matches[1];
vendor['cost'] = matches[2];
}
i++;
vendor['outOfStock'] = vendors[i];
i++;
var records = vendors[i].split('|');
if (records.length >= 2) {
vendor['vendorTable'] = records[0];
vendor['catItemSysid'] = records[1];
}
i++;
data.push(vendor);
}
}
return data;
},
findVendors: function() {
var data = [];
var model = this.request.getParameter('sysparm_model');
gs.info('Model = ' + model);
if (model) {
data = this._getVendors(model);
}
return (new JSON()).encode(data);
},
_getLicensesInternal: function(modelSysId) {
var validLicenses = [];
if (modelSysId) {
/* Get all 'InStock' licenses for the model */
var licenses = this._getRecordObject('alm_license',
[{
key: 'install_status',
value: 1
}, {
key: 'model',
value: modelSysId
}],
['sys_id', 'model', 'rights', 'license_key', 'asset_tag', 'display_name', 'install_state', 'substate', 'vendor']);
/* Update actual available rights from entitlement */
for (var i = 0; i < licenses.length; i++) {
var license = this._getLicenseDetails(licenses[i]);
var available = parseInt(license['available']);
if (isNaN(available) || available == 0)
continue;
validLicenses.push(license);
}
}
return validLicenses;
},
getLicenses: function() {
var validLicenses = [];
var modelSysId = this.request.getParameter('sysparm_model');
validLicenses = this._getLicensesInternal(modelSysId);
return (new JSON()).encode(validLicenses);
},
getLicensesForWorkspace: function(modelSysId) {
var validLicenses = [];
validLicenses = this._getLicensesInternal(modelSysId);
return validLicenses;
},
_getEntitlementsInternal: function(modelSysId) {
var validLicenses = [];
if (modelSysId) {
// Get all licenses for the model with available allocations
var licenses = this._getRecordObject('alm_license',
[{
key: 'install_status',
value: 1
}, {
key: 'model',
value: modelSysId
}, {
key: 'allocations_available',
operator: '>',
value: 0
}, {
key: 'product_type',
operator: '!=',
value: 'maintenance'
}],
['sys_id', 'model', 'rights', 'license_key', 'asset_tag', 'display_name', 'install_state', 'substate', 'vendor', 'allocations_available'], {
'license_metric': {
table: 'samp_sw_license_metric',
fields: ['name', 'metric_group', 'entitlement_type']
}
}
);
// Use the index 'available' for the allocations available (pre-calculated by field)
for (var i = 0; i < licenses.length; i++) {
licenses[i].name = licenses[i].display_name;
licenses[i].available = licenses[i].allocations_available;
validLicenses.push(licenses[i]);
}
}
return validLicenses;
},
// Method used from SW Source request when SAMP is active
getEntitlements: function() {
var validLicenses = [];
var modelSysId = this.request.getParameter('sysparm_model');
validLicenses = this._getEntitlementsInternal(modelSysId);
return (new JSON()).encode(validLicenses);
},
getEntitlementsForWorkspace: function(modelSysId) {
var validLicenses = [];
validLicenses = this._getEntitlementsInternal(modelSysId);
return validLicenses;
},
// Method used from SW Source request when SAMP is active
getLicenseMetrics: function() {
// Retrieve all the existing license metrics grouped by license metric group
var licenseMetrics = {};
var metricGroups;
var lmGr = new GlideRecord('samp_sw_license_metric');
lmGr.orderBy('name');
lmGr.query();
while (lmGr.next()) {
metricGroups = (lmGr.metric_group + '').split(',');
for (var mg = 0; mg < metricGroups.length; mg++) {
if (!licenseMetrics.hasOwnProperty(metricGroups[mg])) {
licenseMetrics[metricGroups[mg]] = [];
}
licenseMetrics[metricGroups[mg]].push({
name: lmGr.name + '',
value: lmGr.sys_id + ''
});
}
}
return (new JSON()).encode(licenseMetrics);
},
_getLicenseDetails: function(license) {
var noOfRights = license.rights;
var unalloCatedDetails;
var allocatedLicenses = 0;
license.name = license.display_name; /* UI Editable Select custom cmponent refern name */
/*
* If SAM is not installed or Model does not have a counter or Counter associated to a model is not ran
* the unallocated rights is calculated based on the entitlements assigned and rights available
*/
if (this._isSAMEnabled() && this._isCounterRan(license.model))
license.unallocated = (new SoftwareItemProcessor()).getUnAllocatedDetails(license);
/* Always have available rights ( total - no of entitlements ) */
license.available = this._getAvailableRights(license.model, license.sys_id);
return license;
},
/*
* Method which checks if the counter assoicated to a model is ran or not.
*/
_isCounterRan: function(modelId) {
var counterGr = new GlideRecord('sam_sw_counter');
counterGr.addQuery('model', modelId);
counterGr.addQuery('cached', true);
counterGr.query();
if (counterGr.next()) {
return true;
}
return false;
},
processRequestInternal: function(scReqSysid, scTaskSysid, data) {
var orderCounts = {
po_order: 0,
to_order: 0,
asgn_order: 0,
lo_order: 0
};
if(this.isEAMActive){
orderCounts.eam_lo_order = 0;
orderCounts.eam_consumable = 0;
}
data = (new JSON()).decode(data);
var response = this._validate(scReqSysid, scTaskSysid, data);
if (response.status == 'success') {
for (var i = 0; i < data.length; i++) {
var consilidateOrders = data[i].consolidate_pos || false;
var reqItem = data[i].req_item_sys_id;
var model = data[i].model;
/* Already sourced quantity */
var sourcedQuantity = data[i].sourced_quantity;
/* toal quantity requested */
var quantity = data[i].quantity;
var remainQuantity = data[i].remain_quantity;
var updatedCount = 0;
/* Process Local Orders */
if (!gs.nil(data[i].local_orders) && data[i].local_orders.length > 0)
updatedCount += this._processLocalOrders(reqItem, model, quantity, sourcedQuantity, remainQuantity, data[i].local_orders, orderCounts);
/* Process Transfer Orders */
if (!gs.nil(data[i].transfer_orders) && data[i].transfer_orders.length > 0)
updatedCount += this._processTransferOrders(reqItem, model, quantity, sourcedQuantity, remainQuantity, data[i].transfer_orders, orderCounts);
/* Handle Software License assignment/entitlement */
if (!gs.nil(data[i].assignments) && data[i].assignments.length > 0)
updatedCount += this._processAssignments(data[i].assignments, scReqSysid, scTaskSysid, orderCounts);
/* Handle Software License entitlements (SAMP) */
if (!gs.nil(data[i].allocations) && data[i].allocations.length > 0)
updatedCount += this._processAllocations(data[i].allocations, scReqSysid, scTaskSysid, orderCounts);
/* Process Purchase orders if any */
if (!gs.nil(data[i].purchase_orders) && data[i].purchase_orders.length > 0) {
updatedCount += this._processPurchaseOrders(reqItem, model, quantity, sourcedQuantity, remainQuantity, data[i].purchase_orders, consilidateOrders, orderCounts);
}
// updating the item
if (updatedCount > 0)
this._updateRequestItemForRemainQuantity(reqItem, model, updatedCount);
}
this._updateSCTaskStatus(scReqSysid, scTaskSysid);
if (this.errorsInRequest) {
response.status = 'error';
response.error_messages = [];
var em = gs.getErrorMessages();
var errorsCount = em.size();
if (errorsCount) {
for (var e = 0; e < errorsCount; e++) {
response.error_messages.push(em.get(e));
}
gs.flushMessages();
} else {
response.error_messages.push(gs.getMessage('Errors encountered in the Source Request process, please check system log'));
}
} else {
response.status = 'success';
response.asgn_count = orderCounts.asgn_order;
}
response.sr_messages = this.sourceRequestMessages(orderCounts);
}
return (new JSON()).encode(response);
},
processRequest: function() {
/* Service catalog task */
var scTaskSysid = this.request.getParameter('sysparm_sc_task');
/* Service catalog request */
var scReqSysid = this.request.getParameter('sysparm_sc_req');
var data = this.request.getParameter('sysparm_sourcedata');
return this.processRequestInternal(scReqSysid, scTaskSysid, data);
},
sourceRequestMessages: function(orderCounts) {
var statusMsg = '';
var status = [];
if (orderCounts.po_order > 0) {
status.push(gs.getMessage('{0} Purchase Order Line(s)', String(orderCounts.po_order)));
}
if (orderCounts.to_order > 0) {
status.push(gs.getMessage('{0} Transfer Order Line(s)', String(orderCounts.to_order)));
}
if (orderCounts.lo_order > 0) {
status.push(gs.getMessage('{0} Consume Asset Task(s)', String(orderCounts.lo_order)));
}
if(this.isEAMActive){
if (orderCounts.eam_lo_order > 0) {
status.push(gs.getMessage('{0} Enterprise Confirm Asset Task(s)', String(orderCounts.eam_lo_order)));
}
if (orderCounts.eam_consumable > 0) {
status.push(gs.getMessage('{0} Local Consumable reservation(s)', String(orderCounts.eam_consumable)));
}
}
if (orderCounts.asgn_order > 0) {
if (this.isSAMPActive) {
status.push(gs.getMessage('{0} License Allocation(s)', String(orderCounts.asgn_order)));
} else {
status.push(gs.getMessage('{0} License Assignment(s)', String(orderCounts.asgn_order)));
}
}
if (status.length == 1) {
statusMsg = gs.getMessage('{0} created successfully.', status);
} else if (status.length == 2) {
statusMsg = gs.getMessage('{0} and {1} created successfully.', status);
} else if (status.length == 3) {
statusMsg = gs.getMessage('{0} , {1} and {2} created successfully.', status);
} else if (status.length == 4) {
statusMsg = gs.getMessage('{0} , {1}, {2} and {3} created successfully.', status);
} else if (status.length == 5) {
statusMsg = gs.getMessage('{0} , {1}, {2}, {3} and {4} created successfully.', status);
}
return statusMsg;
},
_validate: function(scReqSysid, scTaskSysid, submitedData) {
/* Compare submitted data with current data from DB for any concurrent modification */
var currentReqData = this._getRequestData(scReqSysid, scTaskSysid);
for (var index = 0; index < currentReqData.length; index++) {
var currentReqItem = currentReqData[index];
var submittedRegItem = this._getRequestItem(currentReqItem.sys_id, submitedData);
if (submittedRegItem) {
/* Copy user created order lines */
currentReqItem.local_orders = submittedRegItem.local_orders;
currentReqItem.transfer_orders = submittedRegItem.transfer_orders;
currentReqItem.purchase_orders = submittedRegItem.purchase_orders;
currentReqItem.assignments = submittedRegItem.assignments;
currentReqItem.allocations = submittedRegItem.allocations;
} else {
this.log('Unable to find request item with sys_id ' + currentReqItem.sys_id);
}
}
var validator = new SourceRequestValidator(currentReqData);
return validator.validate();
},
_getRequestItem: function(reqItemSysid, reqData) {
for (var i = 0; i < reqData.length; i++) {
if (reqData[i].req_item_sys_id == reqItemSysid)
return reqData[i];
}
},
_processLocalOrders: function(reqItemSysid, model, quantity, sourcedQuantity, remainQuantity, localOrders, orderCounts) {
var assetUtils = new AssetUtils();
var updatedCount = 0;
var reqItemGr = new GlideRecord('sc_req_item');
reqItemGr.get(reqItemSysid);
for (var i = 0; i < localOrders.length; i++) {
var from = localOrders[i].source.sys_id;
var reservedUser = localOrders[i].reservedUser.value;
/* Quantity to be sourced from the source stockroom */
var sourceQuant = localOrders[i].sourceQuantity;
if (!this.isValidLocalOrder(from, reservedUser, sourceQuant)) {
this.log('Skipping invalid local order request. Source: ' + from + ' user:' + reservedUser + ' quantity:' + sourceQuant);
continue;
}
var avail = 0;
try {
avail = assetUtils.getAvailableQuantity(model, from);
} catch (e) {}
var consumeAmount;
if ((avail != 0) && (parseInt(sourceQuant) > 0) && (parseInt(sourceQuant) >= parseInt(avail)))
consumeAmount = parseInt(avail);
if ((avail != 0) && (parseInt(sourceQuant) > 0) && (parseInt(sourceQuant) < parseInt(avail)))
consumeAmount = parseInt(sourceQuant);
var modelGR = new GlideRecord('cmdb_model');
modelGR.get(model);
// checking to see if we are using an asset or a consumable
if (assetUtils.getAssetOrConsumable(modelGR) == 'consumable') {
if (this._createLocalLineTasks(from, reservedUser, consumeAmount, modelGR, reqItemSysid, true)) {
if (this.isEAMActive && this._isValidEAMLocalOrder(reqItemGr)) {
orderCounts.eam_consumable += 1;
}else{
orderCounts.lo_order += 1;
}
updatedCount += consumeAmount;
}
} else {
for (var j = 0; j < consumeAmount; j++) {
if (this._createLocalLineTasks(from, reservedUser, 1, modelGR, reqItemSysid, false)) {
if (this.isEAMActive && this._isValidEAMLocalOrder(reqItemGr)) {
orderCounts.eam_lo_order += 1;
}else{
orderCounts.lo_order += 1;
}
updatedCount += 1;
}
}
}
}
return updatedCount;
},
_isValidEAMLocalOrder: function(reqItemGr){
return !gs.nil(reqItemGr) && ( typeof(reqItemGr.variables.eam_sourcing) !== 'undefined' || typeof (reqItemGr.variables.sn_eam_process) !== 'undefined' || reqItemGr.cat_item.sys_class_name + '' === 'sn_eam_enterprise_cat_item');
},
isValidLocalOrder: function(source, user, quantity) {
if (gs.nil(source) || gs.nil(user) || parseInt(quantity) <= 0)
return false;
else
return true;
},
_processTransferOrders: function(reqItemSysid, model, quantity, sourcedQuantity, remainQuantity, transferOrders, orderCounts) {
var assetUtils = new AssetUtils();
var updatedCount = 0;
for (var i = 0; i < transferOrders.length; i++) {
var from = transferOrders[i].source.sys_id;
var dest = transferOrders[i].destination.value;
/* Quantity to be sourced from the source stockroom */
var sourceQuant = transferOrders[i].sourceQuantity;
if (!this.isValidTransferOrder(from, dest, sourceQuant)) {
this.log('Skipping invalid transfer order request. Source: ' + from + ' dest:' + dest + ' quantity:' + sourceQuant);
continue;
}
var avail = 0;
try {
avail = assetUtils.getAvailableQuantity(model, from);
} catch (e) {}
var transAmount;
if ((avail != 0) && (parseInt(sourceQuant) > 0) && (parseInt(sourceQuant) >= parseInt(avail)))
transAmount = parseInt(avail);
if ((avail != 0) && (parseInt(sourceQuant) > 0) && (parseInt(sourceQuant) < parseInt(avail)))
transAmount = parseInt(sourceQuant);
//ToDo: Understand this piece of code
/*if(transAmount > remain)
var transAmount = parseInt(remain);
}*/
var modelGR = new GlideRecord('cmdb_model');
modelGR.get(model);
// checking to see if we are using an asset or a consumable
if (assetUtils.getAssetOrConsumable(modelGR) == 'consumable') {
if (this._createTransferLine(from, dest, transAmount, modelGR, reqItemSysid, true)) {
orderCounts.to_order += 1;
updatedCount += transAmount;
}
} else {
// creating TOL for assets
for (var j = 0; j < transAmount; j++) {
if (this._createTransferLine(from, dest, 1, modelGR, reqItemSysid, false)) {
orderCounts.to_order += 1;
updatedCount += 1;
}
}
}
} // End of transfer lines
return updatedCount;
},
_processPurchaseOrders: function(reqItemSysid, model, quantity, sourcedQuantity, remainQuantity, purchaseOrders, consolidateOrders, orderCounts) {
var totalCount = 0;
for (var i = 0; i < purchaseOrders.length; i++) {
// making purchase order for the rest of left quantities
//var vendor = eval("vendor_" + i).split('|');
var vendorTable = purchaseOrders[i].vendor.vendorTable;
var catItemId = purchaseOrders[i].vendor.catItemSysid;
var destSysid = purchaseOrders[i].destination.value;
var vendorId;
var vendorPrice = 0;
var listPrice = 0;
var partNumber = '';
var catItemRecord = new GlideRecord(vendorTable);
var item = new GlideRecord("sc_req_item");
item.get(reqItemSysid);
catItemRecord.get('sys_id', catItemId);
if (vendorTable == 'pc_vendor_cat_item' || vendorTable == 'sc_cat_item') {
vendorId = catItemRecord.vendor;
vendorPrice = catItemRecord.price;
listPrice = catItemRecord.list_price;
partNumber = catItemRecord.product_id;
}
// var qRemain = parseInt(item.quantity) - parseInt(item.quantity_sourced);
// item.quantity_sourced = parseInt(qRemain) + parseInt(item.quantity_sourced);
/* NewBehavior: create purchase order for user given quantity */
var purchaseQuantity = Number(purchaseOrders[i].purchaseQuantity);
// item.quantity_sourced = purchaseQuantity + parseInt(item.quantity_sourced);
// if(parseInt(item.quantity_sourced) >= parseInt(item.quantity)) {
// // mark the item as sourced
// item.sourced = true;
// this.hasItemSourced = true;
// }
// item.update();
/* update SC Task for remain quantity or sourced flag */
//this._updateRequestItemForRemainQuantity(reqItemSysid, purchaseQuantity);
totalCount += purchaseQuantity;
var metricGroup;
var licenseMetric;
if (this.isSAMSActive && item.cat_item.model.sys_class_name == 'cmdb_software_product_model') {
metricGroup = purchaseOrders[i].metric_group.value;
licenseMetric = purchaseOrders[i].license_metric.value;
}
(new ProcurementUtils()).createPOLine('', item, purchaseQuantity, vendorId, consolidateOrders, destSysid, vendorPrice, listPrice, metricGroup, licenseMetric, partNumber, model);
orderCounts.po_order++;
}
return totalCount;
},
_createTransferLine: function(fromSysid, destSysid, transAmount, modelGR, reqItemSysid, isConsumable) {
var req = new GlideRecord('alm_transfer_order_line');
req.from_stockroom = fromSysid;
req.to_stockroom = destSysid;
req.model = modelGR.sys_id;
req.quantity_requested = transAmount;
req.request_line = reqItemSysid;
try {
if (!isConsumable) {
req.asset = (new AssetUtils()).getFirstItem(modelGR, fromSysid, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.AVAILABLE_SUBSTATUS);
}
var sysId = req.insert();
return true;
} catch (err) {
this.errorsInRequest++;
gs.error(err);
return false;
}
},
_createLocalLineTasks: function(fromSysid, reservedUser, consumeAmount, modelGr, reqItemSysid, isConsumable) {
var assetId;
var assetGr;
var consumableGr;
var oldReservedFor;
var flowInputs = {};
var flowName;
var isAssetReserved = false;
try {
flowInputs.requested_item = this._getRecordFromId('sc_req_item', reqItemSysid);
flowInputs.reserved_for = this._getRecordFromId('sys_user', reservedUser);
flowInputs.stockroom = this._getRecordFromId('alm_stockroom', fromSysid);
if (!isConsumable) {
assetId = (new AssetUtils()).getFirstItem(modelGr, fromSysid, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.AVAILABLE_SUBSTATUS);
assetGr = this._getRecordFromId('alm_asset', assetId);
oldReservedFor = assetGr.getValue('reserved_for');
assetGr.setValue('install_status', global.AssetUtils.INSTOCK_STATUS);
assetGr.setValue('substatus', global.AssetUtils.RESERVED_SUBSTATUS);
assetGr.setValue('reserved_for', reservedUser);
if (assetGr.update()) {
isAssetReserved = true;
}
} else {
consumableGr = global.ProcurementUtils.getConsumble(modelGr, flowInputs.stockroom, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.AVAILABLE_SUBSTATUS, consumeAmount);
assetId = new Consumables().split(consumableGr.sys_id, consumeAmount, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.RESERVED_SUBSTATUS, '', consumableGr.stockroom, consumableGr.location, '');
if (assetId) {
isAssetReserved = true;
}
assetGr = global.ProcurementUtils.getConsumble(modelGr, flowInputs.stockroom, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.RESERVED_SUBSTATUS, consumeAmount);
}
// if eam plugin is active and reqItem is associated with EAM WO CAT Item then skip Asset local Order subflow and trigger enterprise local order subflow
if(this.isEAMActive && sn_eam.EAMSourcingAutomationAPI && sn_eam.EAMSourcingAutomationAPI.triggerLocalorder ){
var contextId = sn_eam.EAMSourcingAutomationAPI.triggerLocalorder(assetGr , consumeAmount ,reqItemSysid , reservedUser ,fromSysid , isConsumable);
if(!gs.nil(contextId))
return true;
}
flowInputs.asset = assetGr;
flowInputs.quantity = consumeAmount;
flowName = this._getFlowDecision(flowInputs);
sn_fd.FlowAPI.startSubflow(flowName, flowInputs);
return true;
} catch (err) {
this.errorsInRequest++;
if (isAssetReserved) {
this._revertAssetChanges(assetGr, oldReservedFor, modelGr, flowInputs.stockroom, consumeAmount, isConsumable);
}
gs.error(err);
return false;
}
},
_getRecordFromId: function(table, sysId) {
var gr = new GlideRecord(table);
if (gr.get(sysId)) {
return gr;
}
throw gs.getMessage('Record with sys_id {0} not found in {1}', [sysId, table]);
},
_getFlowDecision: function(flowInputs) {
var defaultFlow = 'global.asset_local_order';
var DECISION_ID = 'fb6220090f321010967863cda8767edf';
var dtAPI = new sn_dt.DecisionTableAPI();
var inputs = new Object();
inputs.asset = flowInputs.asset.sys_id;
inputs.requested_item = flowInputs.requested_item.sys_id;
inputs.requested_for = flowInputs.reserved_for.sys_id;
inputs.model = flowInputs.asset.model.sys_id;
inputs.stockroom = flowInputs.stockroom.sys_id;
var response;
try {
response = dtAPI.getDecision(DECISION_ID, inputs);
defaultFlow = response.sys_scope.scope + '.' + response.internal_name;
} catch (err) {
gs.error(err);
}
if (!global.AssetUtils.isFlowPresent(defaultFlow.split('.')[1])) {
throw gs.getMessage('The subflow named: {0} does not exist',
[defaultFlow.split('.')[1]]);
}
return defaultFlow;
},
_revertAssetChanges: function(asset, reservedFor, model, stockroom, consumeAmount, isConsumable) {
var assetGr;
var consumableId;
var consumableGr;
if (!isConsumable) {
assetGr = this._getRecordFromId('alm_asset', asset.sys_id);
assetGr.setValue('install_status', global.AssetUtils.INSTOCK_STATUS);
assetGr.setValue('substatus', AssetUtils.AVAILABLE_SUBSTATUS);
assetGr.setValue('reserved_for', reservedFor);
assetGr.update();
} else {
consumableGr = global.ProcurementUtils.getConsumble(model, stockroom, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.RESERVED_SUBSTATUS, consumeAmount);
consumableId = new Consumables().split(consumableGr.sys_id, consumeAmount, global.AssetUtils.INSTOCK_STATUS,
global.AssetUtils.AVAILABLE_SUBSTATUS, '', consumableGr.stockroom, consumableGr.location, '');
}
},
/*Update request item record with remaining quantity or completed sourced */
_updateRequestItemForRemainQuantity: function(reqItemSysid, model, transAmount) {
var item = new GlideRecord("sc_req_item");
item.get(reqItemSysid);
// item.quantity = item.quantity - transAmount;
if (this.isEAMActive && sn_eam.EAMProcSourceRequestManager &&
sn_eam.EAMProcSourceRequestManager.prototype._EAMupdateRequestItemForRemainQuantity &&
(typeof(item.variables.sn_eam_asset_process) !== 'undefined') && item.variables.sn_eam_asset_process) {
var eamProcSourceRequestManager = new sn_eam.EAMProcSourceRequestManager();
eamProcSourceRequestManager._EAMupdateRequestItemForRemainQuantity(item, model, transAmount);
} else if (this.isHAMPActive && sn_hamp.HAMProcSourceRequestManager &&
sn_hamp.HAMProcSourceRequestManager.prototype._HAMupdateRequestItemForRemainQuantity &&
(typeof(item.variables.sn_hamp_hw_asset_process) !== 'undefined') && item.variables.sn_hamp_hw_asset_process) {
var hamProcSourceRequestManager = new sn_hamp.HAMProcSourceRequestManager();
hamProcSourceRequestManager._HAMupdateRequestItemForRemainQuantity(item, model, transAmount);
} else {
item.quantity_sourced = parseInt(transAmount) + parseInt(item.quantity_sourced);
var qRemain = parseInt(item.quantity) - parseInt(item.quantity_sourced);
if (qRemain <= 0) {
item.sourced = true;
}
}
item.update();
},
_updateSCTaskStatus: function(scReqSysid, taskSysid) {
if (this._hasAllItemsSourced(scReqSysid)) {
var task = new GlideRecord("sc_task");
task.get(taskSysid);
task.setValue("state", 3);
task.update();
}
},
_hasAllItemsSourced: function(scReqSysid) {
var hasUnsourced = false;
var rq = new GlideRecord('sc_req_item');
rq.addQuery('request', scReqSysid);
rq.addQuery('sourced', 'false');
if (this.isEAMActive && sn_eam.EAMProcSourceRequestManager &&
sn_eam.EAMProcSourceRequestManager.prototype._addEAMRITMFilter &&
(typeof(rq.variables.sn_eam_asset_process) !== 'undefined') && rq.variables.sn_eam_asset_process) {
var eamProcSourceRequestManager = new sn_eam.EAMProcSourceRequestManager();
eamProcSourceRequestManager._addEAMRITMFilter(rq);
} else if (this.isHAMPActive && sn_hamp.HAMProcSourceRequestManager &&
sn_hamp.HAMProcSourceRequestManager.prototype._addHAMRITMFilter) {
var hamProcSourceRequestManager = new sn_hamp.HAMProcSourceRequestManager();
hamProcSourceRequestManager._addHAMRITMFilter(rq);
} else {
rq.addNotNullQuery('cat_item.model');
}
//Ignore Closed Complete, Closed Incomplete and Closed Skipped records
rq.addEncodedQuery('stateNOT IN3,4,7');
rq.setLimit(1);
rq.query();
hasUnsourced = rq.getRowCount() > 0;
return !hasUnsourced;
},
isValidTransferOrder: function(source, dest, quantity) {
if (gs.nil(source) || gs.nil(dest) || parseInt(quantity) <= 0)
return false;
else
return true;
},
_getRecordObject: function(table, queryParams, fields, refMap, orderBy) {
var records = [];
var gr = new GlideRecord(table);
if (table === "sc_req_item") {
gr.addEncodedQuery("stateNOT IN3,4,7");
}
if (queryParams) {
for (var n = 0; n < queryParams.length; n++) {
var qp = queryParams[n];
if (Array.isArray(qp)) {
var q1 = gr.addQuery(qp[0].key, qp[0].operator, qp[0].value);
q1.addOrCondition(qp[1].key, qp[1].operator, qp[1].value);
} else {
if (qp.operator)
gr.addQuery(qp.key, qp.operator, qp.value);
else
gr.addQuery(qp.key, qp.value);
}
}
}
if (orderBy)
gr.orderBy(orderBy);
gr.query();
while (gr.next()) {
var rec = {};
if (table === 'sc_req_item' && !gs.nil(gr.variables.location)) {
rec['requested_location'] = gr.variables.location.sys_id.toString();
rec['requested_location_name'] = gr.variables.location.name.toString();
}
var glideElements = gr.getFields();
rec['sys_id'] = gr.sys_id.toString();
for (var i = 0; i < glideElements.size(); i++) {
var glideElement = glideElements.get(i);
//gs.info('Processing ' + glideElement.getName() + ' - ' + glideElement.getDisplayValue());
if (!gs.nil(glideElement.toString()) && /* if no fields given then consider all otherwise consider specific */
(fields.length == 0 || (fields.length > 0 && fields.indexOf(glideElement.getName()) >= 0))) {
rec[glideElement.getName()] = glideElement.toString();
}
if (refMap && !gs.nil(refMap[glideElement.getName()])) {
var refDetails = refMap[glideElement.getName()];
var refSysid = glideElement.toString();
var refObjs = this._getRecordObject(refDetails.table, [{
key: 'sys_id',
value: refSysid
}], refDetails.fields);
if (!gs.nil(refObjs) && refObjs.length > 0) {
rec[glideElement.getName()] = refObjs[0];
}
}
}
records.push(rec);
}
return records;
},
_processAllocations: function(assignments, scReqSysid, scTaskSysid, orderCounts) {
var totalAsgnCount = 0;
for (var i = 0; i < assignments.length; i++) {
var assignment = assignments[i];
var sysId = this._createAssignment(assignment, scReqSysid, scTaskSysid);
if (gs.nil(sysId)) {
this.log('ERROR: Unexpecting error encounter while inserting entitlement ' + JSON.stringify(assignment));
this.errorsInRequest++;
} else {
totalAsgnCount += (Number)(assignment.quantity); //Increase by quantity
orderCounts.asgn_order++;
}
}
return totalAsgnCount;
},
_processAssignments: function(assignments, scReqSysid, scTaskSysid, orderCounts) {
var totalAsgnCount = 0;
for (var i = 0; i < assignments.length; i++) {
var assignment = assignments[i];
/* Add multiple assignments for given quantity */
for (var count = 0; count < assignment.quantity; count++) {
var sysId = this._createAssignment(assignment, scReqSysid, scTaskSysid);
if (gs.nil(sysId)) {
this.log('ERROR: Unexpecting error encounter while inserting entitlement ' + JSON.stringify(assignment));
this.errorsInRequest++;
} else {
totalAsgnCount++; //Increase by one, count only if the assignment gets created
orderCounts.asgn_order++;
}
}
}
return totalAsgnCount;
},
processAssignments: function(reqItemSysid, model, quantity, sourcedQuantity, remainQuantity, assignments, scReqSysid, scTaskSysid, orderCounts) {
return this._processAssignments(assignments, scReqSysid, scTaskSysid, orderCounts);
},
/* Creates an assignment/entitlement record */
_createAssignment: function(assignment, scReqSysid, scTaskSysid) {
var gr;
if (assignment.asgn_type.value == 'user') {
gr = new GlideRecord('alm_entitlement_user');
gr.setValue('assigned_to', assignment.user.value);
} else if (assignment.asgn_type.value == 'device') {
gr = new GlideRecord('alm_entitlement_asset');
gr.setValue('allocated_to', assignment.device.value);
}
if (gr.isValid()) {
gr.setValue('licensed_by', assignment.license.sys_id);
if (this.isSAMPActive) {
gr.setValue('metric_group', assignment.license.license_metric.metric_group);
gr.setValue('license_metric', assignment.license.license_metric.sys_id);
gr.setValue('quantity', assignment.quantity);
}
var sys_id = gr.insert();
if (gs.nil(sys_id)) {
this.log('ERROR: Unexpecting error encounter while inserting entitlement ' + JSON.stringify(assignment));
this.errorsInRequest++;
return;
}
this._auditLicensesAssigned(sys_id, assignment, scReqSysid, scTaskSysid);
return sys_id;
}
return;
},
/* Keeps records of entitlement done*/
_auditLicensesAssigned: function(almEntitlementSysid, assignment, scReqSysid, scTaskSysid) {
var auditGR = new GlideRecord('alm_licenses_assigned');
auditGR.initialize();
auditGR.setValue('licensed_by', assignment.license.sys_id);
auditGR.setValue('catalog_task', scTaskSysid);
auditGR.setValue('request_no', scReqSysid);
if (assignment.asgn_type.value == 'user')
auditGR.setValue('assigned_to', assignment.user.value);
else if (assignment.asgn_type.value == 'device')
auditGR.setValue('allocated_to', assignment.device.value);
auditGR.setValue('allocation', almEntitlementSysid);
var sys_id = auditGR.insert();
if (gs.nil(sys_id)) {
this.log('ERROR: Unexpecting error encounter while auditing entitlement ' + JSON.stringify(assignment));
this.errorsInRequest++;
return;
}
},
_processCounterRequestInternal: function(softwareModels) {
var models = [];
models = softwareModels.split(",");
var samutil = new SAMUtil();
samutil.beginCountersForModels(models);
},
_getLocation: function(item) {
return item.requested_location ? item.requested_location : item.requested_user.location?item.requested_user.location.sys_id:'';
},
processCounterRequest: function() {
var softwareModels = this.request.getParameter('sysparm_models');
this._processCounterRequestInternal(softwareModels);
},
processCounterRequestForWorkspace: function(softwareModels) {
this._processCounterRequestInternal(softwareModels);
},
log: function(msg) {
gs.info('[ProcSourceRequestManager] ' + msg);
},
// This counter is used to validate there are errors in the system generated by this Script Include process
errorsInRequest: 0,
type: 'ProcSourceRequestManager'
};
/*
* Sets the user prefernce for Distribution Channel
*/
ProcSourceRequestManager.updateDistributionChannelUserPreference = function(distributionChannelFlag) {
var userId = gs.getUserID();
var userPrefGr = new GlideRecord('sys_user_preference');
userPrefGr.addQuery('name','source_through_distribution_channel');
userPrefGr.addQuery('user', userId);
userPrefGr.query();
if(userPrefGr.next()) {
userPrefGr.value = String(distributionChannelFlag);
userPrefGr.update();
}
else {
new global.GlideQuery('sys_user_preference')
.insert({ name: 'source_through_distribution_channel', user: userId, value : String(distributionChannelFlag) })
.get();
}
};
Sys ID
b520d0bcff0302003706ffffffffff5c