Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

Approved Start/End Dates still auto-populating in dmn_demand (after disabling BR)

Cristina Costa
Tera Contributor

I’m working on a Demand configuration in dmn_demand and trying to meet a requirement where the fields approved_start_date and approved_end_date must remain empty in the early lifecycle states (Draft, Submitted, Screening, Qualified). Users should be able to populate them manually later if needed.

I already identified a Business Rule that was copying values from start_date / requested_by into the approved fields and disabled it. However, the issue is still occurring.

From sys_audit I can see that approved_start_date is still being updated multiple times, by different users and at different times, even after disabling that rule. Flow Designer has also been checked and does not appear to be involved.

At this point I’m trying to understand what other mechanisms could still be populating these fields in SPM/Demand. Possible suspects I’m considering:

  • Data Policies on dmn_demand
  • State model / state transition scripts
  • Other out-of-box Business Rules affecting approved dates
  • Hidden baseline/planning logic in Demand configuration

Has anyone seen this behaviour before in Demand where approved dates are automatically derived even after disabling the obvious BR? Any pointers on where else ServiceNow might be enforcing or calculating these values would be appreciated.

1 REPLY 1

bperkins
Tera Contributor

We ran into a similar issue where our Demand Managers are entering Planned Start and End Dates, and those are automatically being copied to the Approved Start and End Dates. Our Portfolio Managers would like the Approved Dates to be entered separately from the initial Planned Dates - to denote actual approval (and not just system-synced dates that may be overlooked during Portfolio Reviews).

 

Not sure what your environment looks like, but we are using Demand Management and Portfolio Planning (Strategic Planning Workspace). We have the Default Mapping Configuration in the Alignment Integration.

 

At the end of the day, the mechanism isn't a Business Rule, Data Policy, state script, or anything visible in the usual places. We've traced it back to a Script Include that appears to be copying the dates.

 

Root cause appears to be OOTB code in the Script Include APWDateUtilsSNC, method populateApprovedDates(). It's called from transformDateFieldsForE2A(), which runs as part of the SPM internal Alignment integration — specifically the "Transform Payload - Execution to Alignment" action inside the sync_data_from_execution_to_alignment subflow, triggered whenever the OOTB "Sync Data from Execution to Alignment" business rule fires on dmn_demand.

 

var APWDateUtilsSNC = Class.create();
APWDateUtilsSNC.prototype = {
    initialize: function() {
    },

	transformDateFieldsForA2E: function(columnName, columnValue, executionTable, executionColumn, columnDataType) {
		var apwFieldMapUtils = new APWFieldMapUtils();
		var execDataType = apwFieldMapUtils._getInternalColumnDataType(executionTable, executionColumn);
		if(columnValue == 'undefined' || gs.nil(columnValue))
			return 'undefined';
		if(execDataType === 'glide_date_time') {
			if(columnDataType == 'glide_date_time') {
				return columnValue;
			} else {
				var gdt = new GlideDateTime();
				gdt.setDisplayValueInternal(columnValue + " 00:00:00");
				return gdt.getValue();
			}
		} else if (execDataType === 'glide_date') {
			if(columnDataType == 'glide_date_time') {
				var gdt = new GlideDateTime(columnValue);
				var date = gdt.getLocalDate();
				return date.getValue();
			} else
				return columnValue;
		}
	},

	transformDateFieldsForE2A : function(columnName, columnValue, executionTable, executionColumn, columnDataType, inputPayload, alignmentTable, executionSysId) {
		var apwFieldMapUtils = new APWFieldMapUtils();
		var execDataType = inputPayload[columnName].data_type;
		if(columnValue == 'undefined' || gs.nil(columnValue)){
			if(alignmentTable == 'sn_align_core_demand' && (executionColumn == 'approved_start_date' || executionColumn == 'approved_end_date'))
				 columnValue = this.populateApprovedDates(executionColumn, inputPayload[columnName], executionSysId);
		    else
				return 'undefined';
		}
			
		if(columnDataType == 'glide_date_time') {
			if(execDataType == 'glide_date_time') {
				return columnValue;
			} else {
				var gdt = new GlideDateTime();
				gdt.setDisplayValueInternal(columnValue + " 00:00:00");
				return gdt.getValue();
			}
		} else {
			if(execDataType == 'glide_date_time') {
				var gdt = new GlideDateTime(columnValue);
				var date = gdt.getLocalDate();
				return date.getValue();
			} else
				return columnValue;
		}
	},

	populateApprovedDates: function(executionColumn, inputPayloadObj, recordSysId) {
		var columnToBeCopiedFrom;
		if(executionColumn == 'approved_start_date')
			columnToBeCopiedFrom = 'start_date';
		else 
			columnToBeCopiedFrom = 'requested_by';
		
		var gr = new GlideRecord('dmn_demand');
		gr.get(recordSysId);
		var sourceValue = gr.getValue(columnToBeCopiedFrom);
		if(!gs.nil(sourceValue)) {
			gr.setValue(executionColumn,sourceValue);
			gr.setWorkflow(false);
			gr.update();
			inputPayloadObj.value = sourceValue;
		}
		return sourceValue;
	},
	
    type: 'APWDateUtilsSNC'
};

 

The logic: if approved_start_date/approved_end_date are empty at the moment of that sync, it copies them from start_date/requested_by — directly, via GlideRecord.update() with setWorkflow(false). That setWorkflow(false) is why it's invisible to Debug Business Rule and doesn't register as a "real" Business Rule execution — it's explicitly bypassing that engine. It's also why Flow Designer looked uninvolved at a glance: the write happens inside a flow action's script, not as an obviously-flagged flow step, so you have to open that specific action's run history to see it.

 

Since this appears to fire on every sync while approved dates are empty, it directly conflicts with keeping the the Approved Dates empty through Draft/Submitted/Screening/Qualified — there's no config flag OOTB as far as we've found to turn it off and appears to be hardcoded.

 

I'm curious if anyone has recommendations on the best practices on this - process-wise or technically? My initial reaction is to have Approved Dates set by the Portfolio Managers first based on business priority, and then Planned Dates set within those boundaries. However, our Portfolio Managers are looking for Planned Dates to be set first for when our delivery teams can do something - prior to approving the dates.